Skip to content

feat(workers): stop and start the worker of a single library - #5846

Merged
cjkindel merged 5 commits into
feat/library-metadata-load-outcomefrom
feat/stop-worker-for-library
Oct 13, 2026
Merged

cjkindel merged 5 commits into
feat/library-metadata-load-outcomefrom
feat/stop-worker-for-library

Conversation

@cjkindel

@cjkindel cjkindel commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #5845 (base branch feat/library-metadata-load-outcome). Part of #5102.

This PR doesn't depend on #5845's code. It sits on top of it only to keep the stack linear.

Problem

The only way to stop workers is reset_workers, which stops all of them and runs only when every library reloads. Anything that changes one library's execution environment has to get that library's worker off it first: the worker holds .venv-exec on its import path, and on Windows its open files can't be deleted. The reset in the next PR is the first caller.

Change

  • WorkerManager.stop_worker_for_library(library_name): stops one library's worker and leaves every other worker running. If that library's spawn is still in progress (claimed, but not yet in the registry), it waits for the spawn to finish, then terminates whatever process it produced. So when it returns, no worker for the library is running or about to start. It fails anything awaiting the worker with WorkerGoneError("... shut down to reset library ...") and unsubscribes its response topic. Worker registrations are read after the termination, so one that registers while its process is stopping is forgotten too. It also records why the library has no worker (note_worker_unavailable), so a node waiting on the readiness gate is released with that reason instead of waiting out the load timeout; expect_worker clears it on the restart. The spawn claim is now an asyncio.Event that the spawn sets when its attempt ends.
  • reset_workers and stop_worker_for_library share one _stop_workers helper. reset_workers still clears every claim without waiting.
  • LibraryWorkers.start_worker_for_library(library_name): starts that library's worker again through _start_workers, which gains an only_library_name filter. The usual rules still apply: a session is required, and unmet requirements and failed execution builds are refused.

Testing

make check and the unit suite pass. New tests:

  • TestStopWorkerForLibrary in test_app_worker.py: only the target process and registration go, an in-progress spawn is waited out and the process it produced is stopped, in-flight requests settle with the reason, and a library with no worker is a no-op, a worker that registers mid-stop is forgotten, and the readiness gate is released with a reason.
  • A filter test and a no-session guard test for start_worker_for_library in test_library_worker_config.py.

The only way to stop workers was reset_workers, which stops all of them and
only runs when every library reloads. Anything that changes one library's
execution environment has to get that library's worker off it first: the
worker holds .venv-exec on its import path, and on Windows its open files
cannot be deleted.

WorkerManager.stop_worker_for_library terminates one library's worker,
fails anything awaiting it with the reason, unsubscribes its response
topic, and drops its spawn claim so a later spawn is admitted. Every other
worker keeps running.

LibraryWorkers.start_worker_for_library starts that library's worker again
through the same _start_workers rules (session required, unmet
requirements and failed execution builds refused), limited to that one
library.
@cjkindel
cjkindel added this pull request to stack #5848 October 9, 2026 20:56
@cjkindel cjkindel self-assigned this Oct 9, 2026
@cjkindel
cjkindel requested a review from a team October 9, 2026 20:57
@griptapeops

griptapeops Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

✅ GriptapeOps finished @cjkindel's request in 4m 12s

  • Read PR and diff
  • Verify findings
  • Post review and status

Review posted at c773e60.

@codecov

codecov Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.93939% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...pe_nodes/retained_mode/managers/library/workers.py 85.71% 1 Missing ⚠️
...ape_nodes/retained_mode/managers/worker_manager.py 96.15% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@griptapeops griptapeops Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Aimed right: a per-library stop is what the next PR's reset needs. 1 correctness finding, 1 design.

  • worker_manager.py:609: a spawn in flight survives the stop and can double-fork on restart.
  • worker_manager.py:583: body duplicates reset_workers.

Comment thread src/griptape_nodes/retained_mode/managers/worker_manager.py Outdated
Comment thread src/griptape_nodes/retained_mode/managers/worker_manager.py
stop_worker_for_library dropped the spawn claim of a spawn suspended between
its claim and the registry write, so the spawn resumed afterwards and
registered a live worker, and a start in that window could fork a second
one. The claim is now an asyncio.Event the spawn sets when its attempt ends,
and the stop waits for it before terminating whatever the spawn produced.

reset_workers and stop_worker_for_library now share _stop_workers, so the
two cannot drift. reset_workers still clears every claim without waiting.
assert not stop.done()

released.set()
await spawn

released.set()
await spawn
await stop
@cjkindel

cjkindel commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@griptapeops re-review

@griptapeops

griptapeops Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

✅ GriptapeOps finished @cjkindel's request in 1m 35s

  • Check prior findings against new head
  • Review commits since c773e60
  • Post review + status

Review posted at ac9ecb9.

@griptapeops griptapeops Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Both findings resolved, and the commits since c773e60 are clean against the rubric.

@cjkindel
cjkindel marked this pull request as ready for review October 9, 2026 21:57
@cjkindel
cjkindel requested review from a team and mcaloud and removed request for a team October 9, 2026 21:57

@mcaloud mcaloud left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nothing blocks the merge, but finding 1 should be fixed before the next PR in the stack starts calling this. The worker ids are now read before the processes are terminated, so a worker that registers during the stop stays in the registry, and that also regresses reset_workers. Finding 2: the stop leaves the library's readiness gate waiting.

  • MEDIUM worker_manager.py:576: read worker_ids after termination, not before
  • MEDIUM worker_manager.py:563: record why the library has no worker, so the readiness gate waiters are released
  • LOW test_library_worker_config.py:508: no test covers the guard on start_worker_for_library

Comment thread src/griptape_nodes/retained_mode/managers/worker_manager.py Outdated
Comment thread src/griptape_nodes/retained_mode/managers/worker_manager.py
Comment thread tests/unit/retained_mode/managers/test_library_worker_config.py
…s waiters

_stop_workers read the worker ids before awaiting termination, so a worker
that registered during that await stayed in the registry: routable to a dead
process, skipped by start_worker_for_library as already registered, and its
response topic left subscribed. reset_workers regressed the same way. The ids
are now read after the termination.

stop_worker_for_library now records why the library has no worker, so a node
waiting on its readiness gate is released with the reason instead of waiting
out the load timeout. expect_worker clears it on the restart.

Adds a test for start_worker_for_library's no-session guard.

@mcaloud mcaloud left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All three findings are fixed in afae20b, and each new test fails if its fix is reverted. Thanks!

@cjkindel
cjkindel added this pull request to the merge queue Oct 13, 2026
Merged via the queue into main with commit d656250 Oct 13, 2026
28 checks passed
@cjkindel
cjkindel deleted the feat/stop-worker-for-library branch October 13, 2026 22:49
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.

2 participants