Skip to content

Commit f654fb4

Browse files
committed
refactor(database): clarify comments on heartbeat write logic to prevent workflow and audit log spamming
1 parent a4e274e commit f654fb4

3 files changed

Lines changed: 25 additions & 12 deletions

File tree

App/FeatureSet/Telemetry/Jobs/ProbeIngest/ProcessProbeIngest.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,11 @@ export async function processIncomingEmailFromQueue(
122122
/*
123123
* Update monitor with last email received time. Heartbeat write:
124124
* single-statement UPDATE, no hooks and no `version` bump. These columns
125-
* trigger no onUpdateSuccess work and Monitor enables no update
126-
* workflow/realtime/audit, so nothing is lost. See
127-
* ServiceService.updateLastSeen.
125+
* trigger no onUpdateSuccess work, and this deliberately drops the
126+
* per-update workflow trigger + audit-log entry Monitor's
127+
* @EnableWorkflow / @EnableAuditLog would otherwise fire on every email
128+
* (those are gated on the model flag, not on ignoreHooks) — a heartbeat
129+
* should not spam workflows/audit. See ServiceService.updateLastSeen.
128130
*/
129131
await MonitorService.updateColumnsByIdWithoutHooks({
130132
id: new ObjectID(monitor._id.toString()),

Common/Server/Services/ServiceService.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,12 @@ export class Service extends DatabaseService<Model> {
207207
* write lock across several round trips and, when an event loop stalls
208208
* mid-`save()` transaction, leaves it open as the head of a lock convoy
209209
* that starves the Postgres connection pool. lastSeenAt is an internal
210-
* liveness timestamp with no update hooks on this model (connected /
211-
* disconnected status is derived from it at read time), so a bare
212-
* single-statement UPDATE is both correct and far cheaper.
210+
* liveness timestamp with no onBeforeUpdate/onUpdateSuccess hooks on this
211+
* model (connected / disconnected status is derived from it at read
212+
* time), so a bare single-statement UPDATE is both correct and far
213+
* cheaper. This also intentionally drops the per-update workflow trigger
214+
* Service's @EnableWorkflow({ update: true }) fired on every heartbeat —
215+
* a liveness ping should not trigger user workflows.
213216
*/
214217
await this.updateColumnsByIdWithoutHooks({
215218
id: serviceId,

Common/Server/Utils/Monitor/MonitorResource.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,10 +318,16 @@ export default class MonitorResourceUtil {
318318
if (!serverMonitorResponse.onlyCheckRequestReceivedAt) {
319319
/*
320320
* Heartbeat write: single-statement UPDATE, no hooks and no
321-
* `version` bump. Monitor enables no update workflow/realtime/
322-
* audit and these heartbeat columns trigger no onUpdateSuccess
323-
* work, so nothing is lost; it also skips the pre-SELECT that
324-
* would reload the large serverMonitorResponse jsonb row. See
321+
* `version` bump. This DELIBERATELY drops the per-update workflow
322+
* trigger and audit-log entry that Monitor's @EnableWorkflow /
323+
* @EnableAuditLog fire on every changed update — the old
324+
* `ignoreHooks: true` did NOT suppress those (they are gated on
325+
* the model flag, not on ignoreHooks), so a heartbeat used to
326+
* spam an on-update workflow + an audit row every ingest. A
327+
* liveness ping should do neither. onUpdateSuccess is inert here
328+
* regardless (gated on status/interval/steps/name/etc., none of
329+
* which are written). Also skips the pre-SELECT that would reload
330+
* the large serverMonitorResponse jsonb row. See
325331
* ServiceService.updateLastSeen.
326332
*/
327333
await MonitorService.updateColumnsByIdWithoutHooks({
@@ -350,8 +356,10 @@ export default class MonitorResourceUtil {
350356

351357
/*
352358
* Heartbeat write: single-statement UPDATE, no hooks and no
353-
* `version` bump; skips the pre-SELECT of the large
354-
* incomingMonitorRequest jsonb row. See
359+
* `version` bump. As with the server-monitor branch above, this
360+
* deliberately drops the per-update workflow trigger + audit-log
361+
* entry Monitor would otherwise fire on every heartbeat, and skips
362+
* the pre-SELECT of the large incomingMonitorRequest jsonb row. See
355363
* ServiceService.updateLastSeen.
356364
*/
357365
await MonitorService.updateColumnsByIdWithoutHooks({

0 commit comments

Comments
 (0)