Forum teuk.org

🦉 Mediabot v3 — Sending the Version Checker Through the Shared AsyncWorker

in Mediabot · started by TeuK · 6d ago

TeuK · 6d ago

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.


🧱 What changed

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

🔁 Behaviour preserved

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.


🛡️ A defensive launcher fallback

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.


🧪 Focused regression

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

🔥 Real IO::Async smoke

The adapter was then exercised with the real IO::Async loop.

Successful worker

SUCCESS:
  local=3.4dev-mb652-local
  remote=3.4dev-mb652-remote
  callback_once=1

Timeout worker

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.


🌍 Real network validation

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 real network fetch completed;
  • local and remote version interpretation remained correct;
  • no fallback reason was required;
  • the callback fired exactly once.

🧪 Full-suite validation

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.


🚧 Still intentionally untouched

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.


🧠 Why Version first?

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.


🏰 Next round

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.


✨ Commit

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.