Skip to content

Overhaul server circular dependencies (unblocks faster @swc/jest test transform) #2946

@enoch85

Description

@enoch85

Background

The server test job intermittently prints:

A worker process has failed to exit gracefully and has been force exited. This is likely caused by tests leaking due to improper teardown. Try running with --detectOpenHandles to find leaks. Active timers can also cause this, ensure that .unref() was called on them.

Investigation found this is not a leaked handle:

  • jest --detectOpenHandles is clean across many runs.
  • node-cache already .unref()s its check-period timer.
  • The message only appears under CPU contention (e.g. yarn turbo test running jest + vitest concurrently).

It's slow ts-jest worker teardown under load — each worker holds a full compiled TS program in memory. The warning is left in place intentionally as a reminder for this overhaul (rather than masked with --forceExit).

The real fix

Migrate the jest transform from ts-jest to @swc/jest (~7x faster, light workers that exit cleanly, no warning). A spike showed this works but SWC's stricter CommonJS live-binding exports turn the codebase's existing circular dependencies into TDZ errors:

ReferenceError: Cannot access 'X' before initialization

So the migration is gated on first breaking those cycles:

  • ~24 forwardRef(() => X) constructor injections across ~12 service files (SettingsService, MediaServerFactory, MediaServerSwitchService, PlexApiService, etc.). These are genuine circular service dependencies.
  • Bidirectional TypeORM entity relations (e.g. CollectionRuleGroup).

Suggested approach

  1. Reduce/break the circular service dependencies where possible (many forwardRefs may be avoidable with better module boundaries).
  2. For unavoidable entity cycles, use TypeORM's Relation<> wrapper + import type on relation properties.
  3. For remaining forwardRef params, type-only-alias the annotation so decoratorMetadata doesn't emit an eager class reference.
  4. Switch the jest transform to @swc/jest and drop the worker-teardown warning.

Context

The warning was surfaced while fixing an unrelated vitest OOM in #2940 (settings-form render loop, fixed in fix/settings-form-render-loop). This overhaul was deliberately scoped out of that fix.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions