Skip to content

Resonate setup - #4794

Open
marcoacierno wants to merge 12 commits into
mainfrom
resonate
Open

marcoacierno wants to merge 12 commits into
mainfrom
resonate

Conversation

@marcoacierno

Copy link
Copy Markdown
Member

What

ToDo

@vercel

vercel Bot commented Aug 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pycon Ready Ready Preview Oct 4, 2026 10:25pm UTC

@claude

claude Bot commented Aug 15, 2026 •

Copy link
Copy Markdown
Contributor

Adds Resonate durable-workflow infrastructure: a resonate_worker management command, pycon/resonate_app.py (singleton, start_workflow, database_step, autodiscovery), settings and the resonate-sdk dependency.

Testing

  • Only the command's reload/URL branching is tested. start_workflow, database_step and _recycle_connections have no tests. database_step is the riskiest part: it does annotation resolution and thread-sensitive ORM execution, and _recycle_connections skips connections inside an atomic block. A test that runs a decorated sync step against the DB would catch regressions.
  • The signal and atexit shutdown paths in _stop_on_shutdown are untested.

Design / error handling

  • start_workflow calls asyncio.run, which raises RuntimeError if called from a running event loop (e.g. an async Strawberry resolver or ASGI view). Either document it as sync-only or fall back to async_to_sync/a thread. It also builds, starts and stops a new client on every call, so it is slow for frequent triggers.
  • Registering "pycon" in INSTALLED_APPS only to make management commands discoverable is a broad side effect. It affects app-label, template and static discovery for the whole project package. Consider placing the command in an existing app instead (or confirm nothing else is affected).
  • on_exit waits up to 5s in an atexit hook. If the loop is blocked in a sync ORM step, stopped is never set and the reloader stalls for the full timeout on every code change. This is acceptable for dev, but worth noting.

@codecov

codecov Bot commented Aug 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 42.72727% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.17%. Comparing base (34b93d4) to head (c525abf).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4794      +/-   ##
==========================================
- Coverage   92.68%   92.17%   -0.52%     
==========================================
  Files         356      358       +2     
  Lines       10569    10679     +110     
  Branches      902      910       +8     
==========================================
+ Hits         9796     9843      +47     
- Misses        662      725      +63     
  Partials      111      111              
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Adds the Python side of the Resonate setup: a shared Resonate instance
workflow modules register against, autodiscovery of `<app>/workflows.py`,
a `resonate_worker` management command running the worker process, and
`start_workflow()` for triggering a workflow from synchronous Django code.

Durable functions execute on an event loop, where the Django ORM refuses
to run, so ORM-using steps are wrapped with `database_step`: it hands the
body to asgiref's thread-sensitive executor (one thread, one connection)
and recycles stale connections, skipping any connection inside an atomic
block since that one belongs to whoever opened the transaction.

The `pycon` package is registered as an app so its project-level
management commands are discoverable; it has no models.
Without `RESONATE_URL` the SDK falls back to its in-process connection,
where `start_workflow` would happily create a promise nothing ever
executes, and the worker would sit listening to itself. Both now fail
loudly instead.
Editing a workflow meant restarting the worker by hand for it to run in
its new shape. It now goes through Django's autoreloader, on by default
under DEBUG and switchable with --reload/--no-reload, the way runserver
behaves.

The reloader runs the worker in a daemon thread and exits the process
from the main thread, where the worker's own signal handlers cannot be
installed, so under it the worker stops from an exit hook instead: its
tasks are released back to the server rather than left to lapse with the
killed process.
The SDK reads RESONATE_URL (and RESONATE_HOST/SCHEME/PORT) from the
environment when it is not told a URL, which is how a test process that
happens to run with those variables set -- a container that also runs the
worker, say -- ends up talking to a real server and reusing promises
between runs. Hiding the environment from the SDK leaves Django settings
as the single source.
The wiring was assembled into a kwargs dict so two of its entries could be
left out conditionally; passing the SDK's own defaults (`url=None`,
`sources=None`) says the same thing in one call.
@marcoacierno
marcoacierno removed this pull request from stack #4823 September 26, 2026 13:53
@marcoacierno
marcoacierno added this pull request to stack #4826 September 26, 2026 13:54
@marcoacierno
marcoacierno marked this pull request as ready for review September 26, 2026 13:55

This branch was successfully deployed

1 active deployment
Preview — c525abf7 Deployed Oct 4, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant