Skip to content

Pulse Monitor: Cost page views nothing unless visitor counting is on - #1011

Merged
AllTerrainDeveloper merged 3 commits into
trunkfrom
update/pulse-visitor-cost
Oct 14, 2026
Merged

AllTerrainDeveloper merged 3 commits into
trunkfrom
update/pulse-visitor-cost

Conversation

@AllTerrainDeveloper

@AllTerrainDeveloper AllTerrainDeveloper commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Why

We claim OpenStation adds no front-end performance penalty. The Pulse Monitor (#1006) bent that: while any admin had the wallpaper or widget open, every uncached front-end page view read and rewrote a ~26 KB wp_options row at shutdown. On a local site that added 6–7 ms to the end of each response, with all visitors contending on one row.

What changes

Page views are opt-in. Front-end page views (visitors, bots) are only counted when an administrator turns on Count site visitors in the Pulse Monitor:

  • Where: Settings → Features → Extended options; new pulse_visitors extended option, default false; filter openstation_pulse_count_visitors.
  • While off, a page view returns before it is classified or written, even with a monitor open.
  • A front-end 5xx still beats. REST, cron, admin traffic and explicit events (comments, logins, orders, publishing) aren't page views and keep beating.
  • The Pulse settings form says visitors aren't counted and where to turn it on.

When something is recorded, nobody waits, and writes are rare and small:

  • Early close. The recorder runs last on shutdown (PHP_INT_MAX) and closes the response first with fastcgi_finish_request() / litespeed_finish_request(). The openstation_pulse_finish_request filter turns this off.
  • One write a second at most. Requests in between are sampled out. Failures (5xx, failed logins) are sampled like everything else, so the site-wide failure rate the trace diagnoses from stays fair. A burst such as a login attack or a crawler never becomes a write per request. Only comments, publishing and orders always write: they are rare and already wrote to the database.
  • Persistent object cache. The log and its gate live in the cache (group openstation_pulse) and never touch the database. The gate is an atomic wp_cache_add with a one-second TTL, so the requests in between never fetch the log.
  • Without an object cache. The log is the non-autoloaded openstation_pulse_log option. It is gated by a tiny autoloaded openstation_pulse_gate timestamp, which is free to check.

Heartbeat. The monitor no longer forces Heartbeat to 15 s. It keeps the user's own Heartbeat rate (OpenStation settings, 15–60 s), since every tick is a full request to the server. A slower rate only means site-wide beats arrive later; the trace still replays them at their real spacing.

Docs:

  • pulse-monitor.md: cost model and delivery.
  • hooks-reference.md: two new filters.
  • data-model.md: gate option, cache location, pulse_visitors.

Measured

wp-env (Apache + mod_php, so no early close), Twenty Twenty-One home page, 100 anonymous requests per run, two rounds. This ran before failures joined the sampling and the cache gate was added; neither changes the default path.

median rows written
no monitor open 22.0 / 23.9 ms 0
monitor open, counting off (default) 21.9 / 23.9 ms 0
monitor open, counting on 22.0 / 21.3 ms 4 / 3

Testing

  • PHPUnit full suite green: 3272 tests. New cases:
    • page views are off by default and turned on by the extended option;
    • one write a second, failures sampled too, comments always written;
    • with an object cache, the log stays out of wp_options and the cache gate samples.
  • Vitest full suite green (6755), tsc clean, ESLint 0 errors, PHPCS clean.

To try:

  1. Open the Pulse wallpaper as an admin.
  2. Browse the front end in a private window: no visitor beats.
  3. Turn on the extended option and reload the shell: visitor beats appear, at most about one a second.

🤖 Generated with Claude Code

Open WordPress Playground Preview

AllTerrainDeveloper and others added 3 commits October 14, 2026 15:53
OpenStation adds nothing to front-end pages, and the monitor now keeps
it that way on the server too. Front-end page views (visitors, bots)
are only counted when an administrator turns on the new `pulse_visitors`
extended option ("Count site visitors in the Pulse Monitor"), off by
default; until then a page view returns before anything is classified
or written, even with a monitor open. A front-end 5xx still beats.

When a request is recorded, the write no longer delays anyone or
weighs on the database:

- The recorder runs last on `shutdown` and closes the response first
  (fastcgi_finish_request / litespeed_finish_request), filterable via
  `openstation_pulse_finish_request`.
- With a persistent object cache the log lives in the cache and never
  touches `wp_options`.
- Without one, ordinary traffic writes the log at most once a second
  (autoloaded `openstation_pulse_gate`); failures and explicit events
  (comments, logins, orders, publishing) always write.

New filter `openstation_pulse_count_visitors` overrides the option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Failures are sampled like everything else (one log write a second at
  most), so the site-wide failure rate stays fair and a burst such as a
  login attack never becomes a write per request. Only comments,
  publishing and orders always write.
- With a persistent object cache the one-second gate is an atomic
  `wp_cache_add`, so the requests in between never fetch the log.
- The monitor no longer forces Heartbeat to 15 s: it keeps the user's
  own rate, since every tick is a full request to the server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@AllTerrainDeveloper
AllTerrainDeveloper enabled auto-merge (squash) October 14, 2026 14:13
@AllTerrainDeveloper
AllTerrainDeveloper merged commit e5d9119 into trunk Oct 14, 2026
7 checks passed
@AllTerrainDeveloper
AllTerrainDeveloper deleted the update/pulse-visitor-cost branch October 14, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant