Commit 954ee5c
authored
fix(webapp): deliver realtime changes with current content when the read replica lags (#3910)
## Summary
When the realtime runs feed (the backend behind the `realtimeBackend`
feature flag) hydrates a change from a Postgres read replica, the read
can race the replica's apply of the very write that triggered it. The
delivered row then carries the previous change's content, and an
isolated final change (for example a last `metadata.set` before a run
goes quiet) is not corrected until the roughly 20 second backstop poll.
Measured against a replica with deliberate apply delay, every delivery
trailed exactly one change behind and a final change stranded for the
full backstop interval.
## Fix
Publishers stamp each change record with the committed row's
`updatedAt`, taken from writes they already perform, so the stamp costs
no extra queries. The router delays its wake hydrate until the replica's
measured lag has passed, anchored to that timestamp: a record that has
already spent longer than the lag in transit is hydrated immediately, so
only the racing leading edge ever waits. After hydrating, a tripwire
compares each row against its record's watermark. Still-stale rows are
withheld and retried briefly, and each detection feeds the lag estimate.
If retries run out, the rows are delivered anyway (liveness over
freshness) and follow-up re-hydrates emit the fresh version through the
normal working-set diff once the replica catches up, with the backstop
as the terminal net.
Replica lag is sampled reader-side only, and only while feeds are
active. Aurora reports live lag via `aurora_replica_status()`; vanilla
Postgres can only report "caught up or not" (mid-apply lag is not
honestly measurable from a replica), so tripwire observations floor the
estimate there. Deployments without a replica resolve to zero lag and
skip the gate entirely. Tunables live under
`REALTIME_BACKEND_NATIVE_REPLICA_LAG_*`, and
`realtime_native.stale_hydrates` plus
`realtime_native.replica_lag_estimate_ms` make replica health
observable.
Two adjacent fixes: a metadata update that writes nothing no longer
publishes a change record, and buffered parent and root metadata
operations now publish when the flusher writes them, so those changes
wake live feeds instead of waiting for the backstop.
For local testing, `docker-compose` gains an opt-in `database-replica`
service (compose profile `replica`) with a configurable
`recovery_min_apply_delay`, which reproduces replica-lag behavior
deterministically. With the gate disabled this rig reproduces the
one-change-behind delivery exactly; with it enabled, deliveries arrive
with current content at roughly the true replica lag, across write rates
faster and slower than the lag itself.1 parent 8dc77c0 commit 954ee5c
13 files changed
Lines changed: 1037 additions & 31 deletions
File tree
- .server-changes
- apps/webapp
- app
- routes
- services
- metadata
- realtime
- v3
- test/realtime
- docker
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
338 | 338 | | |
339 | 339 | | |
340 | 340 | | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
341 | 363 | | |
342 | 364 | | |
343 | 365 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
100 | 100 | | |
101 | 101 | | |
102 | 102 | | |
103 | | - | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
104 | 117 | | |
105 | 118 | | |
106 | 119 | | |
| |||
186 | 199 | | |
187 | 200 | | |
188 | 201 | | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
196 | 214 | | |
197 | 215 | | |
198 | 216 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
87 | | - | |
| 87 | + | |
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | 91 | | |
92 | 92 | | |
| 93 | + | |
93 | 94 | | |
94 | 95 | | |
95 | | - | |
| 96 | + | |
96 | 97 | | |
97 | 98 | | |
98 | 99 | | |
99 | 100 | | |
100 | 101 | | |
| 102 | + | |
101 | 103 | | |
102 | 104 | | |
103 | 105 | | |
| |||
Lines changed: 65 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
33 | 43 | | |
34 | 44 | | |
35 | 45 | | |
| |||
172 | 182 | | |
173 | 183 | | |
174 | 184 | | |
175 | | - | |
| 185 | + | |
176 | 186 | | |
177 | 187 | | |
178 | 188 | | |
179 | 189 | | |
180 | | - | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
181 | 199 | | |
182 | 200 | | |
183 | 201 | | |
| |||
237 | 255 | | |
238 | 256 | | |
239 | 257 | | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
240 | 261 | | |
241 | 262 | | |
242 | 263 | | |
| |||
247 | 268 | | |
248 | 269 | | |
249 | 270 | | |
| 271 | + | |
250 | 272 | | |
251 | 273 | | |
252 | 274 | | |
| |||
262 | 284 | | |
263 | 285 | | |
264 | 286 | | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
265 | 297 | | |
266 | 298 | | |
267 | 299 | | |
| |||
346 | 378 | | |
347 | 379 | | |
348 | 380 | | |
349 | | - | |
| 381 | + | |
350 | 382 | | |
351 | 383 | | |
352 | 384 | | |
| |||
356 | 388 | | |
357 | 389 | | |
358 | 390 | | |
359 | | - | |
| 391 | + | |
360 | 392 | | |
361 | 393 | | |
362 | 394 | | |
363 | 395 | | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
364 | 399 | | |
365 | 400 | | |
366 | 401 | | |
| |||
372 | 407 | | |
373 | 408 | | |
374 | 409 | | |
375 | | - | |
| 410 | + | |
376 | 411 | | |
377 | 412 | | |
378 | 413 | | |
379 | 414 | | |
380 | 415 | | |
381 | 416 | | |
382 | 417 | | |
383 | | - | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
384 | 422 | | |
385 | 423 | | |
386 | 424 | | |
| |||
408 | 446 | | |
409 | 447 | | |
410 | 448 | | |
411 | | - | |
| 449 | + | |
412 | 450 | | |
413 | | - | |
| 451 | + | |
414 | 452 | | |
415 | 453 | | |
416 | 454 | | |
| |||
428 | 466 | | |
429 | 467 | | |
430 | 468 | | |
431 | | - | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
432 | 472 | | |
433 | 473 | | |
434 | 474 | | |
| |||
440 | 480 | | |
441 | 481 | | |
442 | 482 | | |
| 483 | + | |
443 | 484 | | |
444 | 485 | | |
445 | 486 | | |
| |||
454 | 495 | | |
455 | 496 | | |
456 | 497 | | |
| 498 | + | |
457 | 499 | | |
458 | 500 | | |
459 | | - | |
| 501 | + | |
460 | 502 | | |
461 | 503 | | |
462 | 504 | | |
| |||
474 | 516 | | |
475 | 517 | | |
476 | 518 | | |
477 | | - | |
| 519 | + | |
478 | 520 | | |
| 521 | + | |
| 522 | + | |
479 | 523 | | |
480 | 524 | | |
481 | 525 | | |
| |||
493 | 537 | | |
494 | 538 | | |
495 | 539 | | |
496 | | - | |
| 540 | + | |
497 | 541 | | |
498 | 542 | | |
499 | 543 | | |
500 | 544 | | |
501 | 545 | | |
502 | 546 | | |
503 | 547 | | |
504 | | - | |
| 548 | + | |
505 | 549 | | |
506 | 550 | | |
| 551 | + | |
| 552 | + | |
507 | 553 | | |
508 | 554 | | |
509 | 555 | | |
| |||
515 | 561 | | |
516 | 562 | | |
517 | 563 | | |
518 | | - | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
519 | 567 | | |
520 | 568 | | |
521 | 569 | | |
| |||
526 | 574 | | |
527 | 575 | | |
528 | 576 | | |
| 577 | + | |
529 | 578 | | |
530 | 579 | | |
| 580 | + | |
531 | 581 | | |
532 | 582 | | |
533 | 583 | | |
534 | | - | |
| 584 | + | |
535 | 585 | | |
536 | 586 | | |
537 | 587 | | |
| |||
Lines changed: 12 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
16 | 28 | | |
17 | 29 | | |
0 commit comments