Scheduler + Observe

This commit is contained in:
mr
2026-04-29 07:45:41 +02:00
parent 4b9b1b8b91
commit 3be023b9af
20 changed files with 1006 additions and 87 deletions

View File

@@ -30,6 +30,48 @@ func NewSessionExecutionsService(sessionID string) *SessionExecutionsService {
return &SessionExecutionsService{ExecutionsSessionID: sessionID}
}
// ---------------------------------------------------------------------------
// Remote resource registry
//
// Bookings and purchases for remote peers are sent via NATS and stored only on
// the remote peer — they never appear in local MongoDB. CleanupSession would
// therefore miss them entirely. We keep a package-level in-memory registry
// (executionsID → list) that is populated when PropagateCreate routes to a
// remote peer, and consumed (cleared) by CleanupSession so it can emit the
// corresponding REMOVE_RESOURCE NATS messages.
// ---------------------------------------------------------------------------
type remoteResourceEntry struct {
ID string
SchedulerPeerID string
ExecutionsID string
DT tools.DataType
}
var remoteRegistryMu sync.Mutex
var remoteRegistry = map[string][]remoteResourceEntry{}
func trackRemoteResource(executionsID, id, schedulerPeerID string, dt tools.DataType) {
if id == "" {
return
}
remoteRegistryMu.Lock()
remoteRegistry[executionsID] = append(remoteRegistry[executionsID], remoteResourceEntry{
ID: id, SchedulerPeerID: schedulerPeerID, ExecutionsID: executionsID, DT: dt,
})
remoteRegistryMu.Unlock()
}
// consumeTrackedRemotes atomically returns and removes all tracked remote
// resources for the given session.
func consumeTrackedRemotes(executionsID string) []remoteResourceEntry {
remoteRegistryMu.Lock()
defer remoteRegistryMu.Unlock()
entries := remoteRegistry[executionsID]
delete(remoteRegistry, executionsID)
return entries
}
// ---------------------------------------------------------------------------
// DB helpers
// ---------------------------------------------------------------------------
@@ -164,6 +206,11 @@ func (s *SessionExecutionsService) upsertDrafts(
scheduling_resources.GetService().PropagateCreate(
scheduling_resources.FromSchedulerDBObject(dt, bk), bk.GetDestPeer(), dt, request, errCh)
<-errCh
// If this booking/purchase was routed to a remote peer (not stored in
// local DB), register it so CleanupSession can emit REMOVE_RESOURCE later.
if self != nil && bk.GetDestPeer() != self.GetID() {
trackRemoteResource(s.ExecutionsSessionID, bk.GetID(), bk.GetPeerSession(), dt)
}
}
}
}
@@ -184,6 +231,14 @@ func (s *SessionExecutionsService) CleanupSession(request *tools.APIRequest) {
}
}
// Emit NATS REMOVE_RESOURCE for bookings/purchases that were routed to
// remote peers and therefore never stored in local DB. loadSession above
// cannot find them, so we rely on the in-memory registry populated by
// upsertDrafts when PropagateCreate routes to a non-self peer.
for _, entry := range consumeTrackedRemotes(s.ExecutionsSessionID) {
scheduling_resources.EmitNATSRemove(entry.ID, entry.SchedulerPeerID, entry.ExecutionsID, entry.DT)
}
for _, exec := range s.LoadSessionExecs() {
execution.UnregisterExecLock(exec.GetID())
workflow_execution.NewAccessor(adminReq).DeleteOne(exec.GetID())
@@ -227,6 +282,7 @@ func GenerateOrder(
}
func (s *SessionExecutionsService) ConfirmSession(request *tools.APIRequest) error {
adminReq := &tools.APIRequest{Admin: true}
for _, dt := range []tools.DataType{tools.BOOKING, tools.PURCHASE_RESOURCE} {
for _, bk := range s.loadSession(dt) {
bk.SetIsDraft(false)
@@ -239,5 +295,9 @@ func (s *SessionExecutionsService) ConfirmSession(request *tools.APIRequest) err
}
}
}
for _, exec := range s.LoadSessionExecs() {
exec.State = enum.SCHEDULED
utils.GenericRawUpdateOne(exec, exec.GetID(), workflow_execution.NewAccessor(adminReq))
}
return nil
}