69752bd6a2
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/claude-agent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
87 lines
2.0 KiB
Plaintext
87 lines
2.0 KiB
Plaintext
@startuml Event Bus Architecture
|
|
skinparam componentAlign center
|
|
title Event Bus: In-Process Pub/Sub Architecture
|
|
|
|
package "Publishers" {
|
|
[Workflow Goroutine 1\n(album A, LOSSLESS)] as WF1
|
|
[Workflow Goroutine 2\n(album B, LOSSY)] as WF2
|
|
}
|
|
|
|
database "PostgreSQL" as DB {
|
|
[workflow_runs] as WR
|
|
[album_events] as AE
|
|
}
|
|
|
|
package "Event Bus (in-memory)" {
|
|
[Topic: albumA:LOSSLESS] as T1
|
|
[Topic: albumB:LOSSY] as T2
|
|
[Global Subscribers] as GS
|
|
}
|
|
|
|
package "Subscribers" {
|
|
[MonitorAlbumStream\nClient A (album A)] as S1
|
|
[MonitorAlbumStream\nClient B (album A)] as S2
|
|
[SubscribeEvents\nClient C (global)] as S3
|
|
}
|
|
|
|
WF1 --> DB : 1. Write event\n(synchronous)
|
|
WF1 --> T1 : 2. Publish\n(async notification)
|
|
|
|
WF2 --> DB : 1. Write event
|
|
WF2 --> T2 : 2. Publish
|
|
|
|
T1 --> S1 : Ring buffer\n(per subscriber)
|
|
T1 --> S2 : Ring buffer
|
|
T1 --> GS
|
|
T2 --> GS
|
|
|
|
GS --> S3 : Ring buffer
|
|
|
|
note right of DB
|
|
**Source of truth.**
|
|
Events survive restarts.
|
|
Replay via seq numbers.
|
|
end note
|
|
|
|
note right of T1
|
|
**Ephemeral notification.**
|
|
Ring buffer per subscriber.
|
|
Slow subscribers: overwrite oldest.
|
|
No backpressure on publishers.
|
|
end note
|
|
|
|
note bottom of S1
|
|
Client disconnect removes
|
|
subscriber from topic.
|
|
Workflow continues.
|
|
end note
|
|
|
|
== Subscription Lifecycle ==
|
|
|
|
note as N1
|
|
**Subscribe flow:**
|
|
1. Client calls MonitorAlbumStream or SubscribeEvents
|
|
2. Server subscribes to EventBus (per-topic or global)
|
|
3. Server queries DB for historical events (replay)
|
|
4. Server bridges: EventBus → gRPC stream
|
|
5. On disconnect: cleanup func unsubscribes
|
|
|
|
**Topic cleanup:**
|
|
When last subscriber leaves AND workflow completed:
|
|
topic removed from EventBus map.
|
|
end note
|
|
|
|
== Recovery on Restart ==
|
|
|
|
note as N2
|
|
**Server restart recovery:**
|
|
1. Query workflow_runs WHERE status = 'running'
|
|
2. For each stale run:
|
|
- If active download exists → mark completed
|
|
- Otherwise → mark failed ("server restarted")
|
|
3. RecoverOrphanedDownloads reschedules poll jobs
|
|
4. New workflows start fresh (no goroutine resurrection)
|
|
end note
|
|
|
|
@enduml
|