Releases: Automattic/newspack-event-logger-plugins
Releases · Automattic/newspack-event-logger-plugins
Release list
v2.4.42
[2.4.42] - 2026-05-07
Fixed
Newspack_Performance_Aggregator\SettingsSync::maybe_queue_sync— fail-closed polarity now matches the file's documented intent andNewspack_Event_Aggregator\SettingsSync(class-settings-sync.php:113). Previously, missing or non-trueenable_workerswas not treated as "skip" — the test wasisset && false === $config['enable_workers'], which letnull/missing/empty count as "yes hub-mode" and silently fanned tuning settings (log_events,custom_events, etc.) out to remote spokes. The file's own comment ("Only hub nodes (enable_workers=true) should sync settings") was the canonical intent; the code was the bug. New test:SettingsSyncTest::test_maybe_queue_sync_skips_when_workers_unset. (newspack-performance-aggregator/includes/class-settings-sync.php)
v2.4.41
Changed
- Supervisor: removed the supervisor-wide restart-marker file (
{base_directory}/restart_supervisor).check_config()now rebuildsworker_locksfrom theregistered_readers/standalone_workersfilters on every tick (every 15s), so plugin activation/deactivation propagates within one config-check tick without needing a marker.Supervisor::request_restart()now uses the per-lockLock::request_restartchannel on the supervisor's own lock dir (supervisor.lock.d/restart) — unified with the worker restart mechanism.kill_readers()no longer chains a supervisor restart, since the next tick's filter rebuild already drops the killed readers. Activation/deactivation propagation latency is preserved (≤15s).
Behavior preserved; one concept dropped, one detection branch removed, one cross-reference between request_restart() and kill_readers() eliminated.
Tests: 1591 / 1591 pass.
v2.4.40
[2.4.40] - 2026-05-05
Fixed
LogReader::get_live_positions(): self-initialize the Memcached connection. The dashboard'sWorkersControllercalls this static method to read live worker cursor positions; on hubs (wherenewspack-performance-dashboardsis active) and standalone servers (wherenewspack-performance-workersis active),Memcached::init()got called as a side effect of those plugins' REST controllers / cron handlers being constructed during request bootstrap, so subsequentMemcached::get()calls succeeded. On spokes that activate neither plugin (e.g. event-logger + event-jobs + event-dashboards + performance-logger only), nothing in the request lifecycle callsMemcached::init()beforeget_live_positions()queries memcache.Memcached::get()returns null when$memdis unset, so the dashboard always fell through to the 30-second offsetlog fallback — every worker appeared "stalled" except for a brief blip every 30s when the offsetlog flushed.Memcached::init()is idempotent ($init_attemptedguards re-entry), so the lazy init here is a no-op when something else already initialized the connection. (newspack-event-logger/includes/cron/class-log-reader.php)
v2.4.39
[2.4.39] - 2026-05-05
Fixed
- LogManager:
process (start)no longer lands at line 28+ on wp-admin requests.message(),error(),warning(),info()now go throughensure_started()so the very first call from any path triggerslog_process()first, puttingprocess (start)atn=1regardless of which entry point the caller used. Cron/job paths were unaffected (they explicitly calledLog::ensure_started()up front), but admin hooks log viaerror()/warning()long before anystart()happens, leavingprocess (start)stranded at whatever line counter we'd already reached. Re-entry safe —ensure_started()sets$this->started = truebefore callinglog_process(). (newspack-performance-logger/includes/class-log-manager.php) wp eventlog reqgrep: print the request_id as a header at the top of every formatted request, instead of synthesizing it after the entry that happens to haven=1. The old approach assumedprocess (start)was always first; on requests where it landed later the rid line attached to whatever unrelated entry was actually first, which made cross-referencing fragile. New header is always present, always at the top, regardless of entry order. The companionn===1synthesis informat_entry()is removed. (newspack-performance-logger/includes/cli/class-reqgrep-command.php)
v2.4.38
[2.4.38] - 2026-05-05
Changed
- WorkerBase: drop the redundant
[EventLogger] FATAL: ... worker pN died: ...log line thathandle_shutdown()emitted on every PHP fatal. PHP already writes its ownPHP Fatal error: ...entry to the same log, with the same file/line/message — our duplicate just doubled the noise without adding signal. The[EventLogger] EXIT:branch is kept (PHP is silent about cleanexit()/die(), so that line is the only signal those leave behind).
v2.4.35
Changed
- Aggregator: post-spoke-add settings push is now queued via
JobIntakeinstead of called inline. The previous v2.4.33 implementation calledRemoteManager::sync_all_settings([$id])synchronously fromServersController::create_item()/update_item(), which meant the admin "Add Server" REST response could block on outbound HTTP for up to ~3 minutes (REQUEST_TIMEOUT = 15s× 13 synced settings) if the new spoke URL was bad/slow. The newRemoteManager::queue_sync_all_settings( $server_ids )helper iterates thenewspack_event_aggregator_synced_settingsfilter and queues onesync_settingjob per setting viaJobIntake::queue, with the targeted server list embedded in the job payload. JobWorker picks them up within milliseconds and dispatches via the samehandle_job→sync_settingpath the periodic uses; the admin response returns immediately.handle_job'ssync_settingbranch now reads and forwards an optionalserversparameter so per-spoke targeting survives the queue round-trip.
v2.4.34
Fixed
- Jobs / Aggregator:
enable_jobs=falsewas silently destructive. JobRouter and JobWorker never registered, butFirehose::writecontinued accumulatingk:"job"entries fromupdate_optionfan-out,supervisor_periodichealth checks, and any plugin usingJobIntake. Symptom: aggregator settings stop syncing to spokes, FlameBuilder auto-tune writes never apply, and queued jobs sit unread in firehose for hours/weeks until retention deletes them. No errors anywhere — the only visible signal waswp eventlog worker typeslisting firehose-workers without ajob-routerhandler. Two guardrails: (1) the admin Enable Jobs field renders a red dependency warning listing each active feature that requires the job pipeline (Aggregator settings sync, Performance Aggregator fan-out, FlameBuilder auto-tune), so toggling jobs off becomes a deliberate choice with surfaced consequences. (2) The aggregator'ssupervisor_periodiccallback now checksenable_jobsbefore queueing health-check jobs and emits a rate-limited (1/hour)error_logwhen jobs are off but spokes are configured, so the broken state is loud instead of silent.
v2.4.33
Fixed
- Aggregator: settings sync to a freshly-added (or re-enabled) spoke could lag by up to ~15 minutes. Two compounding bugs: (1)
ServerRegistryis a process-lifetime singleton that caches$this->serverson first read; long-running JobWorker processes (which dispatch the periodichealth_checkjob that runssync_all_settings) kept a stale view of the server list until they hitMAX_RUNTIME_SECONDS = 595and respawned, so a new spoke was invisible to in-flight workers. (2) Nothing inServersController::create_item()triggered a sync — the new spoke depended entirely on the next 300-second supervisor periodic tick and a JobWorker with a fresh cache aligning. Fix:RemoteManager::health_check()andsync_all_settings()now callServerRegistry::reset_cache()at the top so each dispatch starts from current data;sync_all_settings()accepts an optional?array $server_idsfor targeted pushes;create_item()and the false→trueenabledtransition inupdate_item()synchronously callRemoteManager::sync_all_settings( [ $id ] )so user-initiated server changes don't depend on the periodic chain.
v2.4.32
Fixed
- Aggregator: SSE slot TTL / heartbeat asymmetry caused 429 "Maximum concurrent SSE streams reached" rate-limiting on spokes after StreamMerger restarts. The browser side runs 5s heartbeat against a 10s slot TTL (2x headroom — slots free within ~5s of disconnect); the aggregator side ran 15s heartbeat against a 300s TTL (20x headroom — slots stayed reserved up to ~285s after a worker exited). With
MAX_SSE_SLOTS = 10peruser_id:ip_hash, a few rapid restart cycles exhausted the pool. BroughtSLOT_TTL_AGGREGATORto 30s (same 2x ratio as browsers) and updated the constant's comment to explain the relationship. - Aggregator: SSE slots are now scoped per-partition instead of sharing the global
MAX_SSE_SLOTS = 10pool with browser tabs and other partitions.Memcached::{acquire,check,touch,release}_sse_slot()andsse_slot_key()accept an optionalint $partition(default-1preserves the browser-style shared pool).SSEControllerBase::start_sse_stream()threads the partition from$connected_datainto the slot acquisition whenis_aggregator=true, and stores it for matching releases/checks. Thefirehose/heartbeatendpoint accepts apartitionarg, andStreamMerger::maybe_send_heartbeat()includes it in the POST so each partition refreshes its own keyed slot. Added a regression test covering pool-independence and partition-scoped lookup.
v2.4.31
Fixed
- Aggregator:
ServerRegistry::is_config_server()readConfig::load_config('full'), but the aggregator plugin registersaggregator_serversin the extended option schema (newspack-event-aggregator.php), which causesload_config('full')to overlay the WP optionevent_logger_aggregator_serversonto the file defaults. Every WP-managed server therefore appeared as a "config-file server," tripping the immutability guards inremove()andupdate()—Removeproduced a generic 500 "Failed to delete server." in the admin UI, andupdate()silently stripped all fields exceptenabled. Switched toConfig::load_config_defaults()so only file-defined servers are flagged. Added a regression test that reproduces the schema-extension scenario. (newspack-event-aggregator/includes/class-server-registry.php,tests/unit/ServerRegistryTest.php)