234 lines
7.8 KiB
Go
234 lines
7.8 KiB
Go
package session
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"oc-scheduler/infrastructure/execution"
|
|
"oc-scheduler/infrastructure/scheduling_resources"
|
|
"sync"
|
|
"time"
|
|
|
|
"cloud.o-forge.io/core/oc-lib/dbs"
|
|
"cloud.o-forge.io/core/oc-lib/models/bill"
|
|
"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/order"
|
|
"cloud.o-forge.io/core/oc-lib/models/resources/purchase_resource"
|
|
"cloud.o-forge.io/core/oc-lib/models/utils"
|
|
"cloud.o-forge.io/core/oc-lib/models/workflow_execution"
|
|
"cloud.o-forge.io/core/oc-lib/tools"
|
|
|
|
oclib "cloud.o-forge.io/core/oc-lib"
|
|
)
|
|
|
|
type SessionExecutionsService struct {
|
|
Mu sync.RWMutex
|
|
ExecutionsSessionID string
|
|
}
|
|
|
|
func NewSessionExecutionsService(sessionID string) *SessionExecutionsService {
|
|
return &SessionExecutionsService{ExecutionsSessionID: sessionID}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DB helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func (s *SessionExecutionsService) sessionIDFilter(field, id string) *dbs.Filters {
|
|
return &dbs.Filters{
|
|
And: map[string][]dbs.Filter{
|
|
field: {{Operator: dbs.EQUAL.String(), Value: id}},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (s *SessionExecutionsService) loadSession(dt tools.DataType) []scheduling_resources.SchedulerObject {
|
|
results := oclib.NewRequestAdmin(oclib.LibDataEnum(dt), nil).Search(
|
|
s.sessionIDFilter("executions_id", s.ExecutionsSessionID), "", true)
|
|
out := make([]scheduling_resources.SchedulerObject, 0, len(results.Data))
|
|
for _, obj := range results.Data {
|
|
out = append(out, scheduling_resources.ToSchedulerObject(dt, obj))
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (s *SessionExecutionsService) LoadSessionExecs() []*workflow_execution.WorkflowExecution {
|
|
adminReq := &tools.APIRequest{Admin: true}
|
|
results, _, _ := workflow_execution.NewAccessor(adminReq).Search(
|
|
s.sessionIDFilter("executions_id", s.ExecutionsSessionID), "", true)
|
|
out := make([]*workflow_execution.WorkflowExecution, 0)
|
|
for _, obj := range results {
|
|
if exec, ok := obj.(*workflow_execution.WorkflowExecution); ok {
|
|
out = append(out, exec)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (s *SessionExecutionsService) loadSessionOrder() *order.Order {
|
|
adminReq := &tools.APIRequest{Admin: true}
|
|
results, _, _ := order.NewAccessor(adminReq).Search(
|
|
s.sessionIDFilter("executions_id", s.ExecutionsSessionID), "", true)
|
|
for _, obj := range results {
|
|
if o, ok := obj.(*order.Order); ok {
|
|
return o
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Session upsert
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func (s *SessionExecutionsService) UpsertSessionDrafts(
|
|
purchases, bookings []scheduling_resources.SchedulerObject,
|
|
execs []*workflow_execution.WorkflowExecution,
|
|
request *tools.APIRequest,
|
|
) {
|
|
adminReq := &tools.APIRequest{Admin: true}
|
|
|
|
for dt, datas := range map[tools.DataType][]scheduling_resources.SchedulerObject{
|
|
tools.BOOKING: bookings,
|
|
tools.PURCHASE_RESOURCE: purchases,
|
|
} {
|
|
existing := map[string]scheduling_resources.SchedulerObject{}
|
|
seen := map[string]bool{}
|
|
for _, bk := range s.loadSession(dt) {
|
|
existing[bk.GetKey()] = bk
|
|
}
|
|
s.upsertDrafts(dt, datas, existing, seen, request)
|
|
for key, prev := range existing {
|
|
if !seen[key] {
|
|
scheduling_resources.GetService().Delete(dt, prev, request)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, old := range s.LoadSessionExecs() {
|
|
execution.UnregisterExecLock(old.GetID())
|
|
workflow_execution.NewAccessor(adminReq).DeleteOne(old.GetID())
|
|
}
|
|
for _, exec := range execs {
|
|
exec.ExecutionsID = s.ExecutionsSessionID
|
|
exec.IsDraft = true
|
|
ex, _, err := utils.GenericStoreOne(exec, workflow_execution.NewAccessor(adminReq))
|
|
if err == nil {
|
|
execution.RegisterExecLock(ex.GetID())
|
|
go execution.WatchDeadline(ex.GetID(), s.ExecutionsSessionID, exec.ExecDate, request)
|
|
}
|
|
}
|
|
|
|
if existing := s.loadSessionOrder(); existing == nil {
|
|
GenerateOrder(purchases, bookings, s.ExecutionsSessionID, request)
|
|
} else {
|
|
for _, purch := range purchases {
|
|
existing.Purchases = append(existing.Purchases,
|
|
scheduling_resources.FromSchedulerObject(tools.PURCHASE_RESOURCE, purch).(*purchase_resource.PurchaseResource))
|
|
}
|
|
for _, b := range bookings {
|
|
existing.Bookings = append(existing.Bookings,
|
|
scheduling_resources.FromSchedulerObject(tools.BOOKING, b).(*booking.Booking))
|
|
}
|
|
utils.GenericRawUpdateOne(existing, existing.GetID(), order.NewAccessor(adminReq))
|
|
}
|
|
}
|
|
|
|
func (s *SessionExecutionsService) upsertDrafts(
|
|
dt tools.DataType,
|
|
datas []scheduling_resources.SchedulerObject,
|
|
existing map[string]scheduling_resources.SchedulerObject,
|
|
seen map[string]bool,
|
|
request *tools.APIRequest,
|
|
) {
|
|
self := scheduling_resources.GetService().Self()
|
|
fmt.Println("upsertDrafts", len(datas), len(existing))
|
|
for _, bk := range datas {
|
|
if self != nil {
|
|
bk.SetSchedulerPeerID(self.PeerID)
|
|
}
|
|
bk.SetExecutionsID(s.ExecutionsSessionID)
|
|
seen[bk.GetKey()] = true
|
|
if prev, ok := existing[bk.GetKey()]; ok {
|
|
bk.SetID(prev.GetID())
|
|
bk.SetIsDraft(false)
|
|
needsConsiders := scheduling_resources.GetService().PropagateWrite(
|
|
scheduling_resources.FromSchedulerDBObject(dt, bk), bk.GetDestPeer(), dt, request)
|
|
if needsConsiders {
|
|
if payload, err := json.Marshal(execution.ConsidersPayload{ID: bk.GetID()}); err == nil {
|
|
go execution.UpdateExecutionState(payload, dt)
|
|
}
|
|
}
|
|
} else {
|
|
errCh := make(chan error, 1)
|
|
scheduling_resources.GetService().PropagateCreate(
|
|
scheduling_resources.FromSchedulerDBObject(dt, bk), bk.GetDestPeer(), dt, request, errCh)
|
|
<-errCh
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Session lifecycle
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func (s *SessionExecutionsService) CleanupSession(request *tools.APIRequest) {
|
|
adminReq := &tools.APIRequest{Admin: true}
|
|
for _, exec := range s.LoadSessionExecs() {
|
|
execution.Unschedule(exec.GetID(), request)
|
|
workflow_execution.NewAccessor(adminReq).DeleteOne(exec.GetID())
|
|
}
|
|
if o := s.loadSessionOrder(); o != nil {
|
|
order.NewAccessor(adminReq).DeleteOne(o.GetID())
|
|
}
|
|
}
|
|
|
|
func GenerateOrder(
|
|
purchases, bookings []scheduling_resources.SchedulerObject,
|
|
executionsID string,
|
|
request *tools.APIRequest,
|
|
) (string, error) {
|
|
newOrder := &order.Order{
|
|
AbstractObject: utils.AbstractObject{
|
|
Name: "order_" + request.PeerID + "_" + time.Now().UTC().Format("2006-01-02T15:04:05"),
|
|
IsDraft: true,
|
|
},
|
|
ExecutionsID: executionsID,
|
|
Purchases: []*purchase_resource.PurchaseResource{},
|
|
Bookings: []*booking.Booking{},
|
|
Status: enum.PENDING,
|
|
}
|
|
for _, purch := range purchases {
|
|
newOrder.Purchases = append(newOrder.Purchases,
|
|
scheduling_resources.FromSchedulerObject(tools.PURCHASE_RESOURCE, purch).(*purchase_resource.PurchaseResource))
|
|
}
|
|
for _, b := range bookings {
|
|
newOrder.Bookings = append(newOrder.Bookings,
|
|
scheduling_resources.FromSchedulerObject(tools.BOOKING, b).(*booking.Booking))
|
|
}
|
|
res, _, err := order.NewAccessor(request).StoreOne(newOrder)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if _, err := bill.DraftFirstBill(res.(*order.Order), request); err != nil {
|
|
return res.GetID(), err
|
|
}
|
|
return res.GetID(), nil
|
|
}
|
|
|
|
func (s *SessionExecutionsService) ConfirmSession(request *tools.APIRequest) error {
|
|
for _, dt := range []tools.DataType{tools.BOOKING, tools.PURCHASE_RESOURCE} {
|
|
for _, bk := range s.loadSession(dt) {
|
|
bk.SetIsDraft(false)
|
|
needsConsiders := scheduling_resources.GetService().PropagateWrite(
|
|
scheduling_resources.FromSchedulerDBObject(dt, bk), bk.GetDestPeer(), dt, request)
|
|
if needsConsiders {
|
|
if payload, err := json.Marshal(execution.ConsidersPayload{ID: bk.GetID()}); err == nil {
|
|
go execution.UpdateExecutionState(payload, dt)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|