Skip to content

v0.2.16

Choose a tag to compare

@github-actions github-actions released this 06 Sep 08:22
· 35 commits to main since this release

Typecheck the tests the way CI does

Two test files I added yesterday did not compile under tsconfig.tests.json:
one imported HttpKernelRequest/HttpKernelResponse from the barrel, which does
not re-export them, and the other handed BodyParserMiddleware a hand-rolled
object instead of an HttpContext. tsc --noEmit -p . compiles src alone, so
neither showed up locally; pnpm typecheck:tests is the gate, and it is red
on main, which is what blocks the 0.2.16 publish.

Discover scheduled tasks after the modules that declare them

app/modules/** is auto-loaded at the END of the start phase, after every
provider's start(). The scheduler discovered in start(), so a @service
carrying @schedule in a module — where one naturally lives — was read for
before it existed. The task never fired, and nothing said so. Discovery and
the ticker move to ready(), which runs after the autoload; the earlier passes
stay because they are idempotent and cost nothing.

A test process can now serve HTTP while declaring itself as 'test'. It could
not before: a bootstrap had to call httpServer() to get a server, and that set
the environment to 'web', so a provider entry's environment: ['web'] — the
declarative way to keep a scheduler out of a test run — excluded nothing and
the ticker fired mid-suite.

Read PORT and middleware config where the app can see them

PORT was read at Ignitor construction, but #start/env — the import that
loads .env — only runs in booting(). A PORT living in .env therefore did not
exist yet: the server bound 3000 while the banner, built later from the same
variable, announced 3007. It is now read where HOST already was, when the
socket binds, and refused by name when it is not a port.

BodyParserMiddleware and SessionMiddleware take their settings from
config/bodyparser.ts and config/session.ts when the container builds them,
which is what router.use([() => import('@c9up/ream/session_middleware')])
does. Neither could be registered that way before: there was no path from a
config file to the instance, and an optional constructor parameter still
counts toward Function.length, so the container refused to construct either
one.

Run clippy as a gate, not a note

cargo fmt --check was gating the formatting while nothing gated the
lints that catch a real defect — the one place the compiler stays silent
and clippy does not. Nine of the ten crates in this cohort had the same
hole; only one ran it.

No version change: this gates what is already there, and every crate
passes it today.

Release 0.2.16

Stop the scheduler from being a reason the process lives

Scheduler.register() builds a NAPI ThreadsafeFunction per task, and a
ThreadsafeFunction holds Node's event loop referenced for as long as it
lives. stop() cancels the tick loop, but the callbacks live on in the
task registry — so a process that had merely REGISTERED a task never
exited. Every console command booting an app that carries a @Schedule
ran its work to completion and then hung until a timeout or the operator
killed it, which is exactly what makes such a command unusable from cron.

The control experiment: start/stop with no task registered exits at once;
with one task it is still alive minutes later. And nothing in JS could
point at it — process.getActiveResourcesInfo() reports an empty list,
because the reference is held below what Node can report.

The task callbacks are weak now. That is the honest shape: a scheduler is
a side concern, not a reason for a process to exist. A server is held open
by its listener, and a long-running scheduler process by the command that
runs it, the way queue:work holds its own — no shipped command relied on
the old behaviour, schedule:run and schedule:list both return.

create_threadsafe_fn is untouched and stays strong for the HTTP listener
and the event bus, where the reference IS the reason to keep running.

Three tests spawn real processes and check they end, because a reference
invisible to JS cannot be asserted from inside the process holding it.


Changes since v0.2.15.