Skip to content

Emit events for deployment create, update, and delete operations#21139

Merged
desertaxle merged 3 commits intomainfrom
devin/1773689161-deployment-crud-events
Mar 17, 2026
Merged

Emit events for deployment create, update, and delete operations#21139
desertaxle merged 3 commits intomainfrom
devin/1773689161-deployment-crud-events

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Mar 16, 2026

Adds event emission for deployment CRUD operations (prefect.deployment.created, prefect.deployment.updated, prefect.deployment.deleted), following the same patterns used for work pool and work queue events.

Closes #20176

Changes

src/prefect/server/models/events.py

  • Extracts _deployment_related_resources helper from deployment_status_event to build related resources (flow, work-queue, work-pool) shared across all deployment events
  • Adds deployment_created_event, deployment_updated_event, deployment_deleted_event factory functions

src/prefect/server/models/deployments.py

  • create_deployment: Captures a upsert_start timestamp before the upsert, then compares result_deployment.created >= upsert_start to reliably distinguish create vs update (same pattern used by the API layer for HTTP status codes). Snapshots field values into a plain dict before the upsert for change detection on the update path. Calls session.expire() on the pre-loaded ORM object to prevent stale state after the upsert.
  • update_deployment: Snapshots deployment field values before and after update; emits updated event with changed field details (from/to values). Calls session.expire() after snapshotting.
  • delete_deployment: Reads deployment and builds the delete event before deletion (while the object is still in session); emits deleted event after successful delete.
  • delete_deployments: Loads full deployment objects (instead of just IDs) so delete events can be built before the bulk delete, then emits them after.
  • Adds DEPLOYMENT_EVENT_FIELDS set (includes version, concurrency_limit_id, concurrency_options alongside the original fields), _detect_deployment_changed_fields helper, and emit_* wrapper functions

tests/server/orchestration/api/test_deployments.py

  • 8 integration tests covering create, upsert-update, PATCH-update, no-op update, delete, nonexistent delete, bulk delete, and work-pool related resources
  • Updates existing TestGetScheduledFlowRuns assertions to expect new prefect.deployment.created events alongside prefect.deployment.ready events

Updates since last revision

Addressed two review comments:

  1. Race condition in concurrent upserts (P1): Replaced the pre-upsert existence check (existing_snapshot is None) with a timestamp comparison (result_deployment.created >= upsert_start) to determine create-vs-update. Under concurrent POSTs for the same (flow_id, name), both transactions could previously observe "not found" and both emit created events. Now the second request correctly detects the row already existed and emits an updated event instead.

  2. Expanded tracked fields (P2): Added version, concurrency_limit_id, and concurrency_options to DEPLOYMENT_EVENT_FIELDS so that concurrency limit changes and version updates emit prefect.deployment.updated events.

Key review areas

  • Timestamp-based create detection: create_deployment uses result_deployment.created >= upsert_start (mirroring the API layer's HTTP 201 logic). Relies on timestamp precision not being truncated by the DB below the resolution of now("UTC").
  • concurrency_limit_id change detection: Concurrency limit changes are applied via _create_or_update_deployment_concurrency_limit, which modifies the ORM relationship. The post-upsert re-read (via populate_existing=True in create, or read_deployment in update) should pick up the new concurrency_limit_id value, but worth verifying this path works end-to-end.
  • Extra DB reads per operation: create_deployment adds one pre-upsert query; update_deployment adds a pre-update read and a post-update read. Verify this performance trade-off is acceptable.
  • session.expire() after snapshotting: In create_deployment and update_deployment, the existing ORM object is expired after its field values are copied into a plain dict. This prevents stale state when downstream code (e.g. _create_or_update_deployment_concurrency_limit) later accesses the object via session.get(). Verify this doesn't cause unexpected lazy-load behavior.
  • delete_deployments now loads full objects instead of just IDs. The .unique() call was added. Confirm this doesn't change existing return behavior or cause issues at scale.

Checklist

  • This pull request references any related issue by including "closes <link to issue>"
  • If this pull request adds new functionality, it includes unit tests that cover the changes
  • If this pull request removes docs files, it includes redirect settings in mint.json.
  • If this pull request adds functions or classes, it includes helpful docstrings.

Link to Devin session: https://app.devin.ai/sessions/6e878425faa64628980a64c78a432911
Requested by: @desertaxle

- Add _deployment_related_resources helper to build related resources for
  deployment events (flow, work-queue, work-pool)
- Add deployment_created_event, deployment_updated_event, and
  deployment_deleted_event factory functions in server/models/events.py
- Refactor deployment_status_event to use shared helper
- Add emit wrapper functions in server/models/deployments.py
- Integrate event emission into create_deployment (upsert), update_deployment,
  delete_deployment, and delete_deployments (bulk)
- Detect changed fields for update events using DEPLOYMENT_EVENT_FIELDS set
- Add integration tests for all CRUD event scenarios

Closes #20176

Co-authored-by: alex.s <[email protected]>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration
Copy link
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 and CI monitoring

@github-actions github-actions bot added the enhancement An improvement of an existing feature label Mar 16, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 16, 2026

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing devin/1773689161-deployment-crud-events (7871929) with main (ba5a447)

Open in CodSpeed

- Use session.expire() instead of session.expunge() to keep ORM objects
  in the identity map while forcing re-fetch on next access
- Update existing test assertions to expect new deployment.created events
  alongside deployment.ready events

Co-authored-by: alex.s <[email protected]>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Copy link
Contributor Author

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 6 additional findings.

Open in Devin Review

Copy link
Collaborator

@zzstoatzz zzstoatzz left a comment

Choose a reason for hiding this comment

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

lgtm!

@desertaxle desertaxle marked this pull request as ready for review March 17, 2026 15:45
Copy link

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

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: 9de89417cb

ℹ️ 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".

…and expand tracked fields

- Use result_deployment.created >= upsert_start to reliably determine
  whether the upsert was a genuine insert or an ON CONFLICT update,
  fixing a race condition under concurrent POSTs for the same deployment.
- Add version, concurrency_limit_id, and concurrency_options to
  DEPLOYMENT_EVENT_FIELDS so concurrency limit changes and version
  updates emit prefect.deployment.updated events.

Co-authored-by: alex.s <[email protected]>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@desertaxle desertaxle merged commit 3e80a03 into main Mar 17, 2026
75 of 76 checks passed
@desertaxle desertaxle deleted the devin/1773689161-deployment-crud-events branch March 17, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement An improvement of an existing feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Emit events for Deployment actions

2 participants