Repository navigation
fix: Send checkpoints from resource hooks after their resources - #419
Conversation
…ks-and-checkpoint-order
…d skip unchanged state values
…into fix/checkpoint-review-followups
…-followups # Conflicts: # cloudquery/sdk/internal/checkpoint.py # cloudquery/sdk/stateclient/stateclient.py # tests/scheduler/checkpoints.py
…ecutor's private copy
erezrokah
left a comment
There was a problem hiding this comment.
Please address the checkpoint-ordering regression described in the inline comment.
| if self.mem.get(key) == value: | ||
| # a pending change of the key summarizes this caller's resources too | ||
| if key in self.changes: | ||
| self.changes[key].add(scope) | ||
| return |
There was a problem hiding this comment.
[P1] Preserve checkpoint dependencies for unchanged cursor values
After flush() clears self.changes, this early return drops the caller’s scope entirely. For example, resolver A flushes cursor=1; resolver B yields a parent with an unfinished child, then sets and flushes the same cursor; resolver C subsequently flushes cursor=2. B’s flush now schedules no dependency, allowing checkpoint 2 onto the stream before B’s child. An interrupted sync can therefore persist a cursor past rows it never received. Please preserve resource dependencies for unchanged writes in checkpoint mode, even when suppressing redundant state writes.
There was a problem hiding this comment.
Good catch, fixed in 2346dea. set_key now skips an unchanged value only when it writes to the backend directly. With checkpoints, an unchanged value still records the caller's scope, so B's flush sends a checkpoint that waits for B's child, and checkpoint 2 waits for it in turn. test_unchanged_values_order_later_checkpoints_after_the_callers_resources reproduces your A/B/C scenario and fails on the previous commit.
🤖 I have created a release *beep* *boop* --- ## [0.1.56](v0.1.55...v0.1.56) (2026-10-20) ### Bug Fixes * Reject state changes from resolvers of an ended sync ([#417](#417)) ([bbd5b2e](bbd5b2e)) * Send checkpoints from resource hooks after their resources ([#419](#419)) ([fe8cc8f](fe8cc8f)) * Use the computed queue size for child resolver pools ([#416](#416)) ([0a4b408](0a4b408)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
#### Summary With checkpoints, setting a key to the value it already had recorded nothing if the key had no pending change. A later value of the key could then reach the stream before the rows of the resolver that set the unchanged value, so the CLI could save a cursor past rows it never received. `SetKey` now records the caller's resources for unchanged values in checkpoint mode, and still skips them when it writes to the backend directly. The same issue was found and fixed in the Python SDK in cloudquery/plugin-sdk-python#419.
Checkpoints flushed while a resource is being resolved, for example from
pre_resource_resolveorpost_resource_resolve, now wait for that resource and its relations. Before, the scheduler ran a resource's hooks before putting the resource on the queue, so the CLI could save a cursor past rows it never received.Also:
SyncNotRunningError, aRuntimeErrorexported fromcloudquery.sdk.stateclient.max_workersinstead of readingThreadPoolExecutor's private copy, and a comment explains why the queue limit is a semaphore taken beforesubmit().