Bohan Jiang and multica-agent
9a5d8a52f3
fix(timezone): harden hourly-rollup rollout against straight-through migrate MUL-2488 ( #2998 )
...
* fix(timezone): harden hourly-rollup rollout against straight-through migrate
MUL-2488
PR #2968 introduced the new task_usage_hourly rollup but assumed operators
would stop migrate between 102 and 103 to run the one-shot
cmd/backfill_task_usage_hourly. Two pieces made that unsafe in practice:
1. The Dockerfile only shipped server / multica / migrate, so a deployed
container has no backfill binary to run between phases.
2. cmd/migrate has no per-version stop, and entrypoint.sh runs `migrate up`
to the latest version, so 103 silently drops the legacy daily rollups
even when nobody ran the backfill — leaving usage dashboards at zero
despite source data being intact in task_usage.
Changes:
- Build cmd/backfill_task_usage_hourly into the runtime image alongside
the other binaries so operators can `docker exec` the backfill instead
of needing a source checkout.
- Add a fail-closed plpgsql guard at the top of migration 103 that
aborts the migration when task_usage has rows but task_usage_hourly is
empty. Fresh databases (no task_usage rows) are exempt because the new
triggers from 102 will populate the hourly table on the first event.
Already-applied databases are unaffected — schema_migrations tracks by
version only, so 103 is not re-run.
Co-authored-by: multica-agent <[email protected] >
* fix(timezone): use watermark coverage for hourly-rollup guard
The previous check only required `task_usage_hourly` to be non-empty,
which an interrupted backfill or a manual `rollup_task_usage_hourly_window`
call both satisfy. The completion signal we actually trust is
`task_usage_hourly_rollup_state.watermark_at` — backfill only stamps it
to `now() - 5 min` after every monthly slice succeeded, and the cron
worker only advances it on a real tick. Default after migration 101 is
`1970-01-01`, so an unrun or partial backfill is trivially detected.
Also corrects the comment about fresh-install behavior: the triggers in
102 only enqueue dirty keys for agent_task_queue / issue / task_usage
DELETE — they do not write hourly rows. INSERT/UPDATE flows through the
`updated_at` watermark window of `rollup_task_usage_hourly()`, which
only runs once the operator registers it as a pg_cron job.
Co-authored-by: multica-agent <[email protected] >
---------
Co-authored-by: multica-agent <[email protected] >
2026-05-21 16:26:42 +08:00
..
2026-03-20 17:55:49 +08:00
2026-03-24 18:12:06 +08:00
2026-03-23 18:31:25 +08:00
2026-03-23 18:31:25 +08:00
2026-03-23 18:34:51 +08:00
2026-03-23 18:34:51 +08:00
2026-03-24 12:03:14 +08:00
2026-03-24 12:03:14 +08:00
2026-03-24 12:03:14 +08:00
2026-03-24 12:03:14 +08:00
2026-03-24 15:59:11 +08:00
2026-03-24 15:59:11 +08:00
2026-03-24 18:12:06 +08:00
2026-03-24 18:12:06 +08:00
2026-03-25 15:17:59 +08:00
2026-03-25 15:17:59 +08:00
2026-03-26 14:32:30 +08:00
2026-03-26 14:32:30 +08:00
2026-03-26 14:32:30 +08:00
2026-03-26 14:32:30 +08:00
2026-03-26 14:32:30 +08:00
2026-03-26 14:32:30 +08:00
2026-03-26 15:44:10 +08:00
2026-03-26 17:17:23 +08:00
2026-03-26 18:28:36 +08:00
2026-03-26 18:28:36 +08:00
2026-03-27 15:49:30 +08:00
2026-03-27 15:49:30 +08:00
2026-03-28 19:33:20 +08:00
2026-03-28 19:33:20 +08:00
2026-03-28 19:33:20 +08:00
2026-03-28 20:24:07 +08:00
2026-03-28 21:53:08 +08:00
2026-03-28 21:53:08 +08:00
2026-03-28 22:04:35 +08:00
2026-03-28 22:04:35 +08:00
2026-03-29 00:22:17 +08:00
2026-03-29 00:22:17 +08:00
2026-03-29 16:49:55 +08:00
2026-03-29 16:49:55 +08:00
2026-03-29 16:53:28 +08:00
2026-03-29 16:53:28 +08:00
2026-03-29 17:01:07 +08:00
2026-03-29 17:01:07 +08:00
2026-03-29 17:52:35 +08:00
2026-03-29 17:52:35 +08:00
2026-03-30 03:08:52 +08:00
2026-03-30 03:08:52 +08:00
2026-03-30 13:26:42 +08:00
2026-03-30 13:26:42 +08:00
2026-03-30 16:49:13 +08:00
2026-03-30 16:49:13 +08:00
2026-03-30 22:37:59 +08:00
2026-03-30 22:37:59 +08:00
2026-03-30 22:53:28 +08:00
2026-03-30 22:53:28 +08:00
2026-03-30 22:37:59 +08:00
2026-03-30 22:37:59 +08:00
2026-03-31 13:48:39 +08:00
2026-03-31 13:48:39 +08:00
2026-03-31 15:29:41 +08:00
2026-03-31 15:29:41 +08:00
2026-03-31 16:19:02 +08:00
2026-03-31 16:19:02 +08:00
2026-03-31 16:13:58 +08:00
2026-03-31 16:13:58 +08:00
2026-03-31 15:47:09 +08:00
2026-03-31 15:47:09 +08:00
2026-04-02 17:33:52 +08:00
2026-04-02 17:33:52 +08:00
2026-04-07 22:02:28 +08:00
2026-04-07 22:02:28 +08:00
2026-04-09 12:43:21 +08:00
2026-04-09 14:00:03 +08:00
2026-04-09 13:38:46 +08:00
2026-04-09 13:38:46 +08:00
2026-04-08 13:08:15 +08:00
2026-04-08 13:08:15 +08:00
2026-04-09 14:19:46 +08:00
2026-04-09 17:18:14 +08:00
2026-04-09 12:43:21 +08:00
2026-04-09 14:00:03 +08:00
2026-04-09 14:59:16 +08:00
2026-04-09 14:59:16 +08:00
2026-04-09 16:31:05 +08:00
2026-04-09 16:31:05 +08:00
2026-04-10 14:34:32 +08:00
2026-04-10 14:34:32 +08:00
2026-04-10 14:29:00 +08:00
2026-04-10 14:29:00 +08:00
2026-04-10 16:21:20 +08:00
2026-04-10 16:21:20 +08:00
2026-04-10 19:00:25 +08:00
2026-04-10 19:00:25 +08:00
2026-04-10 20:59:32 +08:00
2026-04-10 20:59:32 +08:00
2026-04-13 16:47:56 +08:00
2026-04-13 16:47:56 +08:00
2026-04-14 18:21:11 +08:00
2026-04-14 18:21:11 +08:00
2026-04-15 14:58:53 +08:00
2026-04-15 14:58:53 +08:00
2026-04-15 00:01:18 +08:00
2026-04-15 00:01:18 +08:00
2026-04-15 04:54:37 +08:00
2026-04-15 04:54:37 +08:00
2026-04-16 13:16:35 +08:00
2026-04-16 13:16:35 +08:00
2026-04-15 13:48:21 +08:00
2026-04-15 13:48:21 +08:00
2026-04-16 13:16:35 +08:00
2026-04-16 13:16:35 +08:00
2026-04-16 13:16:35 +08:00
2026-04-16 13:16:35 +08:00
2026-04-18 01:35:22 +08:00
2026-04-18 01:35:22 +08:00
2026-04-17 13:40:02 +08:00
2026-04-17 13:40:02 +08:00
2026-04-16 18:54:12 +08:00
2026-04-16 18:54:12 +08:00
2026-04-16 21:21:20 +08:00
2026-04-16 21:21:20 +08:00
2026-04-17 15:10:38 +08:00
2026-04-17 15:10:38 +08:00
2026-04-19 23:21:31 -07:00
2026-04-19 23:21:31 -07:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 00:06:34 +08:00
2026-04-21 00:06:34 +08:00
2026-04-21 14:42:52 +08:00
2026-04-21 14:42:52 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-21 20:32:33 +08:00
2026-04-22 13:08:37 +08:00
2026-04-22 13:08:37 +08:00
2026-04-22 15:08:06 +08:00
2026-04-22 15:08:06 +08:00
2026-04-23 10:35:55 +08:00
2026-04-23 10:35:55 +08:00
2026-04-24 11:05:33 +08:00
2026-04-24 11:05:33 +08:00
2026-04-27 14:23:42 +08:00
2026-04-27 14:23:42 +08:00
2026-05-06 16:16:12 +08:00
2026-05-06 16:16:12 +08:00
2026-04-29 14:50:58 +08:00
2026-04-29 14:50:58 +08:00
2026-05-03 10:51:31 +08:00
2026-05-03 10:51:31 +08:00
2026-04-29 14:05:26 +08:00
2026-04-29 14:05:26 +08:00
2026-04-29 14:50:58 +08:00
2026-04-29 14:50:58 +08:00
2026-04-29 18:29:46 +08:00
2026-04-29 18:29:46 +08:00
2026-04-29 18:29:46 +08:00
2026-04-29 18:29:46 +08:00
2026-04-29 22:51:29 +02:00
2026-04-29 22:51:29 +02:00
2026-04-30 16:05:53 +08:00
2026-04-30 16:05:53 +08:00
2026-04-30 14:00:43 +08:00
2026-04-30 14:00:43 +08:00
2026-04-30 14:17:53 +08:00
2026-04-30 14:17:53 +08:00
2026-04-30 15:50:05 +08:00
2026-04-30 15:50:05 +08:00
2026-05-06 16:27:06 +08:00
2026-05-06 16:27:06 +08:00
2026-05-09 05:49:33 +02:00
2026-05-09 05:49:33 +02:00
2026-05-07 15:45:29 +08:00
2026-05-07 15:45:29 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-08 15:35:21 +08:00
2026-05-09 15:07:57 +08:00
2026-05-09 15:07:57 +08:00
2026-05-09 14:39:10 +08:00
2026-05-09 14:39:10 +08:00
2026-05-12 13:49:03 +08:00
2026-05-12 13:49:03 +08:00
2026-05-09 15:07:57 +08:00
2026-05-09 15:07:57 +08:00
2026-05-11 14:39:35 +08:00
2026-05-11 14:39:35 +08:00
2026-05-11 14:39:35 +08:00
2026-05-11 14:39:35 +08:00
2026-05-12 10:57:54 +08:00
2026-05-12 10:57:54 +08:00
2026-05-11 22:53:07 +08:00
2026-05-11 22:53:07 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 12:51:16 +08:00
2026-05-13 12:51:16 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-13 18:46:20 +08:00
2026-05-14 14:07:26 +08:00
2026-05-14 14:07:26 +08:00
2026-05-14 15:23:36 +02:00
2026-05-14 15:23:36 +02:00
2026-05-18 12:17:39 +08:00
2026-05-18 12:17:39 +08:00
2026-05-17 15:01:38 +08:00
2026-05-17 15:01:38 +08:00
2026-05-16 21:26:30 +02:00
2026-05-16 21:26:30 +02:00
2026-05-16 21:26:30 +02:00
2026-05-16 21:26:30 +02:00
2026-05-18 14:59:40 +08:00
2026-05-18 14:59:40 +08:00
2026-05-19 05:35:18 +02:00
2026-05-19 05:35:18 +02:00
2026-05-20 12:30:10 +08:00
2026-05-20 12:30:10 +08:00
2026-05-19 18:37:48 +02:00
2026-05-19 18:37:48 +02:00
2026-05-20 05:30:13 +02:00
2026-05-20 05:30:13 +02:00
2026-05-19 19:51:28 +02:00
2026-05-19 19:51:28 +02:00
2026-05-20 15:37:23 +08:00
2026-05-20 15:37:23 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 16:26:42 +08:00
2026-05-21 15:33:47 +08:00
2026-05-21 15:33:47 +08:00