Skip to content

refactor(watcher): effectify FileWatcher as scoped service#17601

Closed
kitlangton wants to merge 14 commits intoeffectify-watcherfrom
effectify-file-watcher-service
Closed

refactor(watcher): effectify FileWatcher as scoped service#17601
kitlangton wants to merge 14 commits intoeffectify-watcherfrom
effectify-file-watcher-service

Conversation

@kitlangton
Copy link
Contributor

Summary

  • Convert FileWatcher from Instance.state namespace to an Effect ServiceMap.Service with scope-based lifecycle
  • Wire FileWatcherService into the per-instance LayerMap so watchers are created/destroyed with each instance
  • Use Effect.timeout and Effect.catchCause for subscribe error handling instead of promise-based withTimeout
  • Read directory and project from InstanceContext instead of global Instance singletons
  • Add watcher integration tests covering create/change/delete events, non-git roots, cleanup, and git metadata filtering

Stacked on #17544.

Testing

  • bun run test test/file/watcher.test.ts
  • bunx tsgo --noEmit

Convert FileWatcher from Instance.state namespace to an Effect
ServiceMap.Service with proper scope-based lifecycle management.
The @parcel/watcher callback fires from a native C++ uv_async handle
which does not preserve Node.js AsyncLocalStorage context. Wrap the
callback in Instance.provide to restore the instance ALS context so
Bus.publish can resolve instance-scoped state and directory.
Add Instance.bind(fn) which captures the current instance ALS context
and returns a wrapper that synchronously restores it when called. This
prevents silent failures when callbacks fire outside the instance async
context (native addons, event emitters, timers).

Use it in FileWatcherService to bind the @parcel/watcher callback,
replacing the async Instance.provide workaround.
@kitlangton kitlangton force-pushed the effectify-file-watcher-service branch from a9a847d to 1ff0d3b Compare March 15, 2026 15:10
…pace

Use Effect.Config.boolean with ConfigProvider (defaults to env) so
tests can override flags via ConfigProvider.layer without module
mocking. Removes mock.module that was poisoning Flag getters and
causing cross-test pollution in config/instruction tests.
Document Instance-scoped services, Instance.bind for ALS context
in native callbacks, and the Flag → Effect.Config migration pattern.
@kitlangton kitlangton force-pushed the effectify-file-watcher-service branch from f5481e2 to cea3f2c Compare March 15, 2026 15:42
@kitlangton kitlangton force-pushed the effectify-file-watcher-service branch from daa2d73 to 3e532b2 Compare March 15, 2026 15:52
@kitlangton kitlangton force-pushed the effectify-file-watcher-service branch from 5b04de9 to e88538a Compare March 15, 2026 16:23
Probe both root and git watcher readiness before asserting events so the watcher tests stop racing startup. Also make the PTY ordering test use a deterministic short-lived process and keep native PTY callbacks bound to the instance context.
@kitlangton kitlangton force-pushed the effectify-file-watcher-service branch from e88538a to 330f315 Compare March 15, 2026 16:28
- Use property shorthand `{ init }` in catchCause fallback
- Make BusUpdate.directory required (non-optional)
- Use Effect.runSync instead of Effect.runFork in synchronous callback
@kitlangton kitlangton force-pushed the effectify-file-watcher-service branch from de4b21f to 59cf7e5 Compare March 15, 2026 16:37
The deny path is synchronous once the Effect runs, but the
ManagedRuntime can take >100ms to start on slow CI runners.
Just await the result directly — bun's 30s test timeout is
the backstop if it ever hangs.
When w.subscribe() takes longer than SUBSCRIBE_TIMEOUT_MS and
eventually resolves, the subscription was left active and unmanaged.
Now the catchCause handler explicitly unsubscribes it, matching
the old withTimeout cleanup behavior.
@kitlangton kitlangton deleted the branch effectify-watcher March 16, 2026 16:55
@kitlangton kitlangton closed this Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant