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

@@ -10,6 +10,8 @@ import (
"oc-scheduler/infrastructure/planner"
oclib "cloud.o-forge.io/core/oc-lib"
"cloud.o-forge.io/core/oc-lib/config"
"cloud.o-forge.io/core/oc-lib/dbs"
"cloud.o-forge.io/core/oc-lib/models/booking"
"cloud.o-forge.io/core/oc-lib/models/common/enum"
"cloud.o-forge.io/core/oc-lib/models/peer"
@@ -221,6 +223,9 @@ func (s *SchedulingResourcesService) Delete(dt tools.DataType, bk SchedulerObjec
if dt == tools.BOOKING {
planner.GetPlannerService().RefreshSelf(selfID.PeerID, request)
}
if (dt == tools.BOOKING || dt == tools.PURCHASE_RESOURCE) && config.GetConfig().IsNano {
SendRemoveToMaster(bk, dt)
}
return
}
EmitNATSRemove(bk.GetID(), bk.GetPeerSession(), bk.GetExecutionsId(), dt)
@@ -299,8 +304,14 @@ func DraftTimeout(id string, dt tools.DataType) {
switch dt {
case tools.BOOKING:
booking.NewAccessor(adminReq).DeleteOne(id)
if config.GetConfig().IsNano {
SendRemoveToMaster(res, dt)
}
case tools.PURCHASE_RESOURCE:
purchase_resource.NewAccessor(adminReq).DeleteOne(id)
if config.GetConfig().IsNano {
SendRemoveToMaster(res, dt)
}
}
fmt.Printf("DraftTimeout: %s %s deleted (still draft after 10 min)\n", dt.String(), id)
}
@@ -316,7 +327,6 @@ func (s *SchedulingResourcesService) HandleCreateBooking(bk *booking.Booking, ad
if self == nil {
return false
}
if existing, _, loadErr := booking.NewAccessor(adminReq).LoadOne(bk.GetID()); loadErr == nil && existing != nil {
prev := existing.(*booking.Booking)
if prev.SchedulerPeerID != bk.SchedulerPeerID || prev.ExecutionsID != bk.ExecutionsID {
@@ -329,13 +339,20 @@ func (s *SchedulingResourcesService) HandleCreateBooking(bk *booking.Booking, ad
if !bk.IsDraft && !prev.ExpectedStartDate.IsZero() && prev.ExpectedStartDate.Before(time.Now().UTC()) {
fmt.Println("HandleCreateBooking: expired, deleting", bk.GetID())
booking.NewAccessor(adminReq).DeleteOne(bk.GetID())
if config.GetConfig().IsNano {
SendRemoveToMaster(bk, tools.BOOKING)
}
return false
}
if _, _, err := utils.GenericRawUpdateOne(bk, bk.GetID(), booking.NewAccessor(adminReq)); err != nil {
fmt.Println("HandleCreateBooking: update failed:", err)
return false
}
if config.GetConfig().IsNano {
SendBookingToMaster(bk)
}
planner.GetPlannerService().RefreshSelf(self.PeerID, adminReq)
return !bk.IsDraft
}
@@ -348,6 +365,7 @@ func (s *SchedulingResourcesService) HandleCreateBooking(bk *booking.Booking, ad
fmt.Println("HandleCreateBooking: conflicts with local planner, discarding")
return false
}
bk.IsDraft = true
stored, _, err := booking.NewAccessor(adminReq).StoreOne(bk)
if err != nil {
@@ -355,11 +373,126 @@ func (s *SchedulingResourcesService) HandleCreateBooking(bk *booking.Booking, ad
return false
}
storedID := stored.GetID()
planner.GetPlannerService().RefreshSelf(self.PeerID, adminReq)
time.AfterFunc(10*time.Minute, func() { DraftTimeout(storedID, tools.BOOKING) })
if config.GetConfig().IsNano {
SendBookingToMaster(bk) // TODO : ASK FOR RESPONSE...
}
return false
}
func SendBookingToMaster(booking *booking.Booking) {
self, _ := oclib.GetMySelf()
if booking.GetCreatorID() != self.GetID() {
return
}
d := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).Search(&dbs.Filters{
And: map[string][]dbs.Filter{
"relation": {{Operator: dbs.EQUAL.String(), Value: peer.MASTER}},
},
}, "", false, 0, 1)
for _, dd := range d.Data {
booking.IsDraft = false
booking.FromNano = self.GetID()
m := map[string]interface{}{}
i, err := json.Marshal(m)
if err == nil {
json.Unmarshal(i, &m)
m["peer_id"] = dd.(*peer.Peer).PeerID
if payloadd, err := json.Marshal(m); err == nil {
b, err := json.Marshal(&tools.PropalgationMessage{
DataType: tools.BOOKING.EnumIndex(),
Action: tools.PB_CREATE,
Payload: payloadd,
})
if err == nil {
tools.NewNATSCaller().SetNATSPub(tools.PROPALGATION_EVENT, tools.NATSResponse{
FromApp: "oc-scheduler",
Datatype: tools.BOOKING,
Method: int(tools.PROPALGATION_EVENT),
Payload: b,
})
}
}
}
}
}
func SendRemoveToMaster(obj utils.DBObject, dt tools.DataType) {
self, _ := oclib.GetMySelf()
if obj.GetCreatorID() != self.GetID() {
return
}
d := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).Search(&dbs.Filters{
And: map[string][]dbs.Filter{
"relation": {{Operator: dbs.EQUAL.String(), Value: peer.MASTER}},
},
}, "", false, 0, 1)
for _, dd := range d.Data {
m := map[string]interface{}{}
i, err := json.Marshal(m)
if err == nil {
json.Unmarshal(i, &m)
m["peer_id"] = dd.(*peer.Peer).PeerID
if payloadd, err := json.Marshal(m); err == nil {
b, err := json.Marshal(&tools.PropalgationMessage{
DataType: dt.EnumIndex(),
Action: tools.PB_DELETE,
Payload: payloadd,
})
if err == nil {
tools.NewNATSCaller().SetNATSPub(tools.PROPALGATION_EVENT, tools.NATSResponse{
FromApp: "oc-scheduler",
Datatype: dt,
Method: int(tools.PROPALGATION_EVENT),
Payload: b,
})
}
}
}
}
}
func SendPurchaseToMaster(purchase *purchase_resource.PurchaseResource) {
self, _ := oclib.GetMySelf()
if purchase.GetCreatorID() != self.GetID() {
return
}
d := oclib.NewRequestAdmin(oclib.LibDataEnum(oclib.PEER), nil).Search(&dbs.Filters{
And: map[string][]dbs.Filter{
"relation": {{Operator: dbs.EQUAL.String(), Value: peer.MASTER}},
},
}, "", false, 0, 1)
for _, dd := range d.Data {
purchase.IsDraft = false
purchase.FromNano = self.GetID()
m := map[string]interface{}{}
i, err := json.Marshal(m)
if err == nil {
json.Unmarshal(i, &m)
m["peer_id"] = dd.(*peer.Peer).PeerID
if payloadd, err := json.Marshal(m); err == nil {
b, err := json.Marshal(&tools.PropalgationMessage{
DataType: tools.PURCHASE_RESOURCE.EnumIndex(),
Action: tools.PB_CREATE,
Payload: payloadd,
})
if err == nil {
tools.NewNATSCaller().SetNATSPub(tools.PROPALGATION_EVENT, tools.NATSResponse{
FromApp: "oc-scheduler",
Datatype: tools.PURCHASE_RESOURCE,
Method: int(tools.PROPALGATION_EVENT),
Payload: b,
})
}
}
}
}
}
// HandleCreatePurchase processes an incoming purchase from NATS.
// Returns true if considers must be triggered.
func (s *SchedulingResourcesService) HandleCreatePurchase(pr *purchase_resource.PurchaseResource, adminReq *tools.APIRequest) bool {
@@ -393,6 +526,9 @@ func (s *SchedulingResourcesService) HandleCreatePurchase(pr *purchase_resource.
fmt.Println("HandleCreatePurchase: could not store:", err)
return false
}
if config.GetConfig().IsNano {
SendPurchaseToMaster(pr) // TODO : ASK FOR RESPONSE...
}
storedID := stored.GetID()
time.AfterFunc(10*time.Minute, func() { DraftTimeout(storedID, tools.PURCHASE_RESOURCE) })
return false
@@ -405,14 +541,17 @@ func (s *SchedulingResourcesService) HandleRemoveBooking(p RemoveResourcePayload
return
}
existing := res.(*booking.Booking)
if existing.SchedulerPeerID != p.SchedulerPeerID || existing.ExecutionsID != p.ExecutionsID {
if existing.SchedulerPeerID != p.SchedulerPeerID || existing.ExecutionsID != p.ExecutionsID || existing.IsDraft {
fmt.Println("HandleRemoveBooking: auth mismatch, ignoring", p.ID)
return
}
booking.NewAccessor(adminReq).DeleteOne(p.ID)
d, _, _ := booking.NewAccessor(adminReq).DeleteOne(p.ID)
if self := s.Self(); self != nil {
planner.GetPlannerService().RefreshSelf(self.PeerID, adminReq)
}
if config.GetConfig().IsNano && d != nil {
SendRemoveToMaster(d, tools.BOOKING) // TODO : ASK FOR RESPONSE...
}
}
// HandleRemovePurchase verifies auth and deletes the purchase.
@@ -422,11 +561,14 @@ func (s *SchedulingResourcesService) HandleRemovePurchase(p RemoveResourcePayloa
return
}
existing := res.(*purchase_resource.PurchaseResource)
if existing.SchedulerPeerID != p.SchedulerPeerID || existing.ExecutionsID != p.ExecutionsID {
if existing.SchedulerPeerID != p.SchedulerPeerID || existing.ExecutionsID != p.ExecutionsID || existing.IsDraft {
fmt.Println("HandleRemovePurchase: auth mismatch, ignoring", p.ID)
return
}
purchase_resource.NewAccessor(adminReq).DeleteOne(p.ID)
d, _, _ := purchase_resource.NewAccessor(adminReq).DeleteOne(p.ID)
if config.GetConfig().IsNano && d != nil {
SendRemoveToMaster(d, tools.PURCHASE_RESOURCE) // TODO : ASK FOR RESPONSE...
}
}
// ---------------------------------------------------------------------------