You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
| Cache lookup | O(1) string read with RLock | Every incoming event |
339
346
340
-
**Cache Invalidation:**
347
+
**Cache Recomputation:**
341
348
342
-
The cache is invalidated and recomputed:
349
+
The cache is computed:
343
350
- On HarmonyLite startup
344
351
- When running `harmonylite -cleanup`
345
-
- When a schema change is detected (future: via SQLite update hook on `sqlite_master`)
352
+
- Periodically during schema mismatch pause state (see Section 5)
353
+
354
+
### 5. Schema Mismatch Handling (Pause with Periodic Recompute)
355
+
356
+
When a schema mismatch is detected (hash comparison fails), replication pauses for that shard by NAK-ing the message with a delay. The sequence map is not advanced, so ordering is preserved.
357
+
358
+
**Key Behavior:** During the pause state, HarmonyLite periodically recomputes the local schema hash to detect if DDL has been applied locally. Once schemas match, replication resumes automatically without requiring a restart.
359
+
360
+
```go
361
+
// logstream/replicator.go
362
+
363
+
typeReplicatorstruct {
364
+
// ... existing fields
365
+
schemaCache *SchemaCache
366
+
schemaMismatchAt time.Time// When mismatch first detected
367
+
lastRecomputeAt time.Time// Last time we recomputed during pause
Msg("Schema now matches after recompute, resuming replication")
406
+
r.resetMismatchState()
407
+
return r.db.ReplicateRow(event)
408
+
}
409
+
410
+
log.Warn().
411
+
Str("event_hash", event.SchemaHash[:8]).
412
+
Str("local_hash", newHash[:8]).
413
+
Dur("paused_for", now.Sub(r.schemaMismatchAt)).
414
+
Msg("Schema still mismatched after recompute")
415
+
}
346
416
347
-
### 5. Schema Mismatch Handling (Pause Policy)
417
+
// Still mismatched - NAK and wait
418
+
msg.NakWithDelay(schemaNakDelay)
419
+
returnnil
420
+
}
421
+
422
+
func(r *Replicator) resetMismatchState() {
423
+
r.schemaMismatchAt = time.Time{}
424
+
r.lastRecomputeAt = time.Time{}
425
+
}
426
+
```
427
+
428
+
**Behavior Summary:**
348
429
349
-
When a schema mismatch is detected (hash comparison fails), replication pauses for that shard by NAK-ing the message with a delay. The sequence map is not advanced, so ordering is preserved. Once the local schema is updated, NATS redelivers from the same sequence and replication resumes.
430
+
| State | Action |
431
+
|-------|--------|
432
+
| First mismatch | Recompute hash immediately, NAK if still mismatched |
433
+
| Subsequent NAKs within 5 min | Just NAK (no recompute) |
434
+
| After 5 min pause | Recompute hash, check again |
435
+
| Schema matches after recompute | Resume replication immediately |
436
+
| Schema still mismatched | Log warning with pause duration, continue waiting |
350
437
351
-
**Behavior:** When an incoming event's `SchemaHash` doesn't match the cached local hash, the consumer logs a warning, NAKs with a delay, and does not apply the event.
438
+
**Self-Healing After DDL:**
439
+
440
+
Once DDL is applied locally (e.g., `ALTER TABLE users ADD COLUMN email TEXT`), the next recompute cycle will detect the schema change and resume replication automatically. No restart or manual intervention is required.
441
+
442
+
**Performance During Pause:**
443
+
444
+
- NAK redelivery: every 30 seconds
445
+
- Hash recomputation: every 5 minutes (not every NAK cycle)
446
+
- This minimizes database introspection overhead during prolonged migration windows
352
447
353
448
### 6. Schema Registry via NATS KV
354
449
@@ -504,12 +599,15 @@ harmonylite schema status --cluster
504
599
-[ ] Ensure backward compatibility with old events (CBOR `omitempty`)
505
600
506
601
### Phase 3: Validation and Pause-on-Mismatch
602
+
-[ ] Add `schemaMismatchAt` and `lastRecomputeAt` fields to `Replicator`
603
+
-[ ] Implement `handleSchemaMismatch()` with periodic recompute logic
507
604
-[ ] Add hash comparison in replication hot path (O(1) string comparison)
508
605
-[ ] NAK with delay when schema hash mismatches (pause replication)
606
+
-[ ] Recompute hash on first mismatch and every 5 minutes during pause
607
+
-[ ] Auto-resume when schema matches after recompute
# Replication paused due to schema mismatch (1 = paused, 0 = normal)
641
+
harmonylite_schema_mismatch_paused 1
542
642
```
543
643
644
+
The `harmonylite_schema_mismatch_paused` gauge is the primary metric for troubleshooting. When set to 1, check logs for hash details and apply DDL to the local node.
645
+
544
646
### Health Check Extension
545
647
546
648
Extend existing health check endpoint:
@@ -552,8 +654,7 @@ Extend existing health check endpoint:
552
654
"schema": {
553
655
"status": "warning",
554
656
"schema_hash": "a1b2c3d4e5f6",
555
-
"cluster_consistent": false,
556
-
"mismatched_nodes": [3]
657
+
"paused": true
557
658
}
558
659
}
559
660
}
@@ -565,24 +666,34 @@ Extend existing health check endpoint:
565
666
566
667
### Performing Schema Migrations
567
668
568
-
Schema migrations are performed manually on each node. Incompatible events pause replication until schemas converge.
669
+
Schema migrations are performed manually on each node. Incompatible events pause replication until schemas converge.**No restart is required** - HarmonyLite automatically detects schema changes during the pause state.
# No restart required! Replication resumes once schema matches.
578
677
579
678
# 3. Repeat for other nodes
580
679
# During migration window, nodes with older schemas will pause replication
581
680
582
-
# 4. After all nodes are migrated and restarted, replication resumes automatically
681
+
# 4. After all nodes have the new schema, replication resumes automatically
682
+
```
683
+
684
+
**Optional: Force Immediate Detection**
685
+
686
+
If you don't want to wait for the 5-minute recompute interval:
687
+
688
+
```bash
689
+
# Option A: Restart HarmonyLite (schema hash computed on startup)
690
+
systemctl restart harmonylite
691
+
692
+
# Option B: Run cleanup command
693
+
harmonylite -cleanup -db mydb.db
583
694
```
584
695
585
-
**Note:** During the migration window, nodes with older schemas will pause replication and NATS will redeliver once schemas converge. Events that fail to apply (e.g., constraint violations) can be moved to the dead-letter table for manual inspection.
696
+
**Note:** During the migration window, nodes with older schemas will pause replication and NATS will redeliver once schemas converge. Events that fail to apply (e.g., constraint violations) are moved to the dead-letter table for manual inspection.
0 commit comments