Commit: 504992e
Version: 3.4dev-20260817_091140
MB652 is the first real consumer migration to Mediabot::AsyncWorker.
The shared worker contract introduced in MB651 was deliberately committed without migrating any existing feature. This round takes the next controlled step:
move exactly one existing asynchronous consumer — the Version checker — onto the shared subprocess lifecycle.
Trivia, Achievements, CommandAsync and YouTube remain untouched.
The Version checker no longer owns its own implementation of:
pipe
fork
watch_process
timeout timers
TERM/KILL escalation
child result collection
callback finalisation
That lifecycle is now delegated to:
Mediabot::AsyncWorker
The Version checker keeps responsibility for its own product behaviour:
local version fallback
remote version interpretation
operator-facing error reason
version comparison semantics
This is the separation MB651 was designed for:
AsyncWorker = lifecycle mechanics
Version checker = version policy
The migration intentionally preserves the Version checker’s existing operational contract.
Among the behaviours kept intact:
local version is always available when possible
remote failure is explicit
timeout remains visible
output remains bounded
callback must fire exactly once
synchronous fallback remains available when no event loop exists
The existing Version regression tests were updated so they verify delegation to the shared worker rather than requiring a second private implementation inside Mediabot::Helpers.
The adapter also guards against a failure while starting the shared worker itself.
If Mediabot::AsyncWorker unexpectedly throws during launch, the Version checker must not:
die
become silent
forget the local version
skip its callback
Instead it follows the existing failure contract and reports a clear reason.
That preserves the “never silent” property already protected by previous Version-worker fixes.
The migration was tested against the existing Version and subprocess lifecycle coverage:
138_helpers_getversion_no_curl_shell.t
539_mb317_version_check_async_nonblocking.t
606_mb388_release_version_identity.t
607_mb389_local_startup_semantic_version_compare.t
609_mb391_core_command_release_contract.t
814_mb632_irc_update_command.t
818_mb638_remote_version_diagnosis.t
819_mb639_remote_version_precommit_truth.t
820_mb640_version_check_never_silent.t
821_mb641_version_worker_terminal_truth.t
822_mb642_version_worker_process_watch.t
823_mb643_version_worker_pipe_fork_liveness.t
833_mb651_asyncworker_contract.t
834_mb652_version_asyncworker_migration.t
86_module_structure_sanity.t
Result:
PASSED : 516/516
The adapter was then exercised with the real IO::Async loop.
SUCCESS:
local=3.4dev-mb652-local
remote=3.4dev-mb652-remote
callback_once=1
A deliberately blocked fetch was forced through the shared timeout lifecycle:
TIMEOUT:
local=3.4dev-mb652-local
remote=Undefined
reason=version check timed out
callback_once=1
Result:
REAL_VERSION_ASYNCWORKER_SMOKE=OK
So both the success path and timeout path preserve callback-once semantics through the shared worker.
After the full test suite passed, the migrated Version checker was also tested against the real remote version source.
Observed result:
LOCAL = 3.4dev-20260817_080225
REMOTE = 3.4dev-20260817_080225
REASON = <none>
CALLBACKS = 1
REAL_VERSION_CHECK=OK
RC=0
This is the most important validation of the round:
The entire Mediabot suite passed after the migration:
PASSED : 13338/13338
RC=0
Runtime remained around the usual test-suite duration:
897s
So the first real AsyncWorker consumer migration did not introduce a regression elsewhere in Mediabot.
MB652 does not migrate:
Trivia
Achievements
CommandAsync
YouTube
The deployment remains incremental.
That was a deliberate roadmap rule: prove the abstraction with one comparatively controlled consumer before migrating the more complicated workers.
The Version checker was a good first consumer because it already had extensive lifecycle coverage.
Its historical tests exercise exactly the failure modes a shared worker must preserve:
non-blocking execution
child process completion
process-watch behaviour
pipe/fork liveness
timeouts
terminal result truth
never-silent failure reporting
remote-version diagnosis
That made it possible to distinguish:
AsyncWorker regression
from:
Version-adapter regression
instead of debugging both abstractions at once.
The next migration is the larger one:
Trivia →
Mediabot::AsyncWorker
The profiler already showed why Trivia deserves special care: its async tests dominate a substantial part of the suite runtime and exercise several timeout/retry/process-watch paths.
The plan remains conservative:
migrate Trivia
preserve protocol semantics
preserve retry/rate-limit behaviour
preserve stage deadlines
preserve diagnostics
validate focused tests
validate a real instance
run the full suite
No big-bang refactor.
504992e
🦉 Send the Version Checker Through the Shared AsyncWorker
Version:
3.4dev-20260817_091140
Committed scope:
CHANGELOG.md
VERSION
Mediabot/Helpers.pm
t/cases/539_mb317_version_check_async_nonblocking.t
t/cases/818_mb638_remote_version_diagnosis.t
t/cases/820_mb640_version_check_never_silent.t
t/cases/821_mb641_version_worker_terminal_truth.t
t/cases/822_mb642_version_worker_process_watch.t
t/cases/823_mb643_version_worker_pipe_fork_liveness.t
t/cases/833_mb651_asyncworker_contract.t
t/cases/834_mb652_version_asyncworker_migration.t
The first consumer has crossed the bridge.
Next comes Trivia.
You must be logged in to reply.