@startuml seq_schedule title Flux SCHEDULE — Peer A ↔ Peer B via oc-discovery skinparam sequenceMessageAlign center skinparam sequence { ArrowColor #333333 LifeLineBorderColor #888888 GroupBorderColor #777777 GroupBackgroundColor #FAFAFA NoteBackgroundColor #FFFDE7 NoteBorderColor #CCAA00 BoxBorderColor #555555 } skinparam ParticipantBackgroundColor #FFFFFF participant "Client" as Client box "Peer A" #EAF3FB participant "oc-scheduler A" as SA participant "oc-discovery A" as DA end box box "Peer B" #EAF9EE participant "oc-discovery B" as DB participant "oc-scheduler B" as SB end box ' ══════════════════════════════════════════════════════════════════ Client -> SA : POST /oc/:wfID ' ────────────────────────────────────────────────────────────────── group ① Planification — synchrone (GetBuyAndBook) SA -> SA : workflow.LoadOne(wfID)\nwf.Planify(start, end, instances, …)\nexec.Buy() → purchases [ DestPeerID = B ]\nexec.Book() → bookings [ DestPeerID = B ]\n⇒ WorkflowExecution {\n BookingsState: { booking_id: false }\n PurchasesState: { purchase_id: false }\n } end ' ────────────────────────────────────────────────────────────────── group ② Propagation vers Peer B — goroutines (errCh attend l'envoi NATS, pas la réception par B) SA -> DA : **NATS PUB** · CREATE_RESOURCE\nPURCHASE_RESOURCE { DestPeerID=B, IsDraft=true } note right of DA : oc-discovery A est le\nrécepteur systématique\ndes émissions NATS de SA DA --> DB : **STREAM** · PropalgationMessage\n{ datatype: PURCHASE_RESOURCE } DB -> SB : **NATS SUB** · CREATE_RESOURCE PURCHASE_RESOURCE SA -> DA : **NATS PUB** · CREATE_RESOURCE\nBOOKING { DestPeerID=B, IsDraft=true } DA --> DB : **STREAM** · PropalgationMessage\n{ datatype: BOOKING } DB -> SB : **NATS SUB** · CREATE_RESOURCE BOOKING end ' ────────────────────────────────────────────────────────────────── group ③ Peer B traite — async (ListenNATS goroutine de SB) SB -> SB : StoreOne(purchase, IsDraft=true)\nAfterFunc(10 min → draftTimeout) SB -> DB : **NATS PUB** · PROPALGATION_EVENT\nConsiders { DataType:PURCHASE_RESOURCE,\n id=purchase_id, execution_id } note right of DB : SB émet sur son NATS local\nDB (oc-discovery B) reçoit DB --> DA : **STREAM** · PropalgationMessage\n{ action: Considers, DataType: PURCHASE_RESOURCE } DA -> SA : **NATS SUB** · PROPALGATION_EVENT\n[ FromApp = "oc-discovery" ] SA -> SA : updateExecutionState()\nPurchasesState[ purchase_id ] = true SB -> SB : PlannerCache[self].Check(slot) ✓\nStoreOne(booking, IsDraft=true)\nAfterFunc(10 min → draftTimeout)\nrefreshSelfPlanner() SB -> DB : **NATS PUB** · PROPALGATION_EVENT\nPB_PLANNER { peer_id, schedule, capacities } DB --> DA : **STREAM** · PropalgationMessage\n{ action: PB_PLANNER } DA -> SA : **NATS SUB** · PROPALGATION_EVENT\n[ FromApp = "oc-discovery" ] SA -> SA : storePlanner(PeerB.PeerID, p) SB -> DB : **NATS PUB** · PROPALGATION_EVENT\nConsiders { DataType:BOOKING,\n id=booking_id, execution_id } DB --> DA : **STREAM** · PropalgationMessage\n{ action: Considers, DataType: BOOKING } DA -> SA : **NATS SUB** · PROPALGATION_EVENT\n[ FromApp = "oc-discovery" ] SA -> SA : updateExecutionState()\nBookingsState[ booking_id ] = true\n→ tous true → State = SCHEDULED (DB) end ' ────────────────────────────────────────────────────────────────── group ④ Schedules() finalise — synchrone (concurrent avec ③) SA -> SA : GenerateOrder(purchases, bookings)\nexec.PurgeDraft()\nexec.StoreDraftDefault() → State=SCHEDULED, IsDraft=false\nGenericStoreOne(exec) SA -> DA : **NATS PUB** · PROPALGATION_EVENT [goroutine]\nConsiders { DataType:WORKFLOW_EXECUTION,\n execution, peer_ids:[ PeerB ] } note right of DA : oc-discovery A reçoit\net STREAM vers tous les\npairs listés dans peer_ids DA --> DB : **STREAM** · PropalgationMessage\n{ action: Considers, DataType: WORKFLOW_EXECUTION } DB -> SB : **NATS SUB** · PROPALGATION_EVENT\n[ FromApp = "oc-discovery" ] SB -> SB : confirmExecutionDrafts()\nconfirmResource(booking_id)\n → Booking.IsDraft=false, State=SCHEDULED\nconfirmResource(purchase_id)\n → Purchase.IsDraft=false SA -> Client : **{WorkflowSchedule, Workflow, Executions}** end note over SA, SB ③ et ④ sont concurrents. En pratique : GenerateOrder + écritures DB côté A laissent le temps à B de recevoir et stocker ses drafts avant que A émette le Considers/WORKFLOW_EXECUTION. end note @enduml