Skip to content

Prevent duplicate server-minted state timestamps#22512

Open
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1784105766-flow-run-state-monotonic-timestamp
Open

Prevent duplicate server-minted state timestamps#22512
devin-ai-integration[bot] wants to merge 3 commits into
mainfrom
devin/1784105766-flow-run-state-monotonic-timestamp

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

closes #22511

this PR prevents duplicate server-minted flow-run state timestamps from violating the unique (flow_run_id, timestamp) index on coarse-resolution clocks.

Details

Flow-run state transitions are serialized under the flow-run row lock. A new flow-only global transform performs an indexed lookup for the exact proposed timestamp before timestamp-dependent bookkeeping runs. When a collision exists, it moves the proposed timestamp to one microsecond after the latest persisted state.

The lookup checks the full state history instead of comparing only with the current state, so it also handles runs whose current state was explicitly backdated. Non-colliding backdated timestamps remain unchanged.

The transform runs before SetRunStateTimestamp, SetStartTime, SetEndTime, and IncrementRunTime, keeping the persisted state and denormalized runtime fields consistent.

Tests cover three transitions in one clock tick, a collision with an older historical state after a backdated current state, and timestamp-derived start/end/runtime bookkeeping.

Checklist

Link to Devin session: https://app.devin.ai/sessions/e5441eea296d4ccabca962261cebe43c

On coarse-resolution clocks (notably Windows, ~15.6ms) the server can mint
identical timestamps for consecutive states of a run, violating the unique
(run_id, timestamp) constraint and surfacing as a 409 IntegrityError.

Add an EnsureStateTimestampIsMonotonic global universal transform, applied
first in COMMON_GLOBAL_TRANSFORMS so it runs before the transforms that read
proposed_state.timestamp. When a proposed state's timestamp collides with the
run's current state, nudge it forward one microsecond; explicitly backdated
states are left untouched. Covers flow and task runs uniformly.

Closes #22511
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions github-actions Bot added the bug Something isn't working label Jul 15, 2026
@codspeed-hq

codspeed-hq Bot commented Jul 15, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 8 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing devin/1784105766-flow-run-state-monotonic-timestamp (4cec34c) with main (b749a67)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@desertaxle desertaxle marked this pull request as ready for review July 15, 2026 14:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9968c92662

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/prefect/server/orchestration/global_policy.py Outdated
devin-ai-integration Bot and others added 2 commits July 15, 2026 15:11
Make EnsureStateTimestampIsMonotonic bump a colliding proposed timestamp
past the run's most recent state instead of only deduping against the
immediately preceding state. This fixes the 3+-states-in-one-tick case
(t -> t -> t) flagged in review, where the third state was previously
treated as backdated and still collided with the first persisted state.

A fast path returns early when the proposed timestamp is already strictly
newer than the current state, so normal forward transitions incur no extra
query. Non-colliding backdated timestamps are still preserved.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4cec34ca67

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

RemoveResumingIndicator,
]
return (
[EnsureFlowRunStateTimestampIsUnique]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Apply timestamp de-duplication to task runs too

When task-run states are set through the normal /task_runs/{id}/set_state API, the request model does not carry a timestamp and the route converts it to a full State, so the timestamp is still minted server-side. This new transform is only prepended to GlobalFlowPolicy; GlobalTaskPolicy still runs only COMMON_GLOBAL_TRANSFORMS(), leaving rapid task transitions on coarse-clock hosts able to create duplicate (task_run_id, timestamp) rows and hit the same IntegrityError this change is meant to avoid.

Useful? React with 👍 / 👎.

)
assert latest_timestamp is not None

proposed_state.timestamp = latest_timestamp + timedelta(microseconds=1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep backdated duplicate timestamps near the collision

When an explicitly backdated flow state collides with an old persisted state after the run already has newer states, this assignment moves the proposed state to max(existing) + 1µs. For example, with persisted states at t0 and t10, proposing a historical state at t0 becomes t10 + 1µs, so state-history reads ordered by timestamp and the run timing fields record it as the newest transition rather than a backdated one. The transform should choose the next free timestamp adjacent to the collided historical timestamp instead of always using the latest state.

Useful? React with 👍 / 👎.

Comment on lines +156 to +160
colliding_timestamp = await context.session.scalar(
sa.select(orm_models.FlowRunState.timestamp)
.where(
orm_models.FlowRunState.flow_run_id == context.run.id,
orm_models.FlowRunState.timestamp == proposed_state.timestamp,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip collision queries for normal forward states

For the common case where a proposed flow state is strictly newer than the current state, this new collision check still performs an extra flow_run_state lookup on every transition. These state-setting paths are hot for normal orchestration, so adding a database round trip even when a collision is impossible can regress production throughput; gate the query behind the initial_state/timestamp fast path described by the transform.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: flow-run Pending→Running fails with 409 IntegrityError — duplicate flow_run_state.timestamp (server mints coarse timestamps)

1 participant