14 Commits

Author SHA1 Message Date
pb
cd7ae788b1 didn't put the blocking loop in the right place for post booking 2025-05-27 12:06:10 +02:00
pb
0d96cc53bf transformed the loop that posted the booking on oc-datacenter to a threaded operation where each call is done in a goroutine 2025-05-27 11:58:55 +02:00
pb
66fc3c5b35 added the passing of the request.Caller's URL to the deep copy 2025-05-27 11:34:44 +02:00
pb
5ab3eb8a38 forgot to pass the mutex as pointer and unlock it 2025-05-27 11:17:10 +02:00
pb
fec23b4acd modified HTTP caller to have a DeepCopy() method in order to parallelize calls without race conditions 2025-05-27 11:08:35 +02:00
pb
901622fee0 logging on the booking uuid before the post booking 2025-05-27 09:51:41 +02:00
pb
527e622774 correct the error channel 2025-05-26 19:21:28 +02:00
pb
7223b79fe8 correct the error channel 2025-05-26 19:16:39 +02:00
pb
1ade41aeae moved the code that execute the booking into a separated function so that it can be launched as goroutine and parallelize get booking$ 2025-05-26 19:05:17 +02:00
pb
58dc579255 added debug logging 2025-05-26 18:30:56 +02:00
pb
370dac201b In CheckBooking mooved the loop on bookings outside of the loop of execs, which seems to repeat the Peer execution on booking an exponential number of time 2025-05-26 17:55:45 +02:00
pb
2a763006db counting round in exec 2025-05-26 17:41:26 +02:00
pb
522c66653b Added logging for debug 2025-05-26 17:22:09 +02:00
pb
b57f050b81 increased the limit of returns by Mongo find() 2025-05-22 14:41:38 +02:00
3 changed files with 104 additions and 32 deletions

View File

@@ -287,7 +287,7 @@ func (m *MongoDB) Search(filters *dbs.Filters, collection_name string) (*mongo.C
return nil, 503, err return nil, 503, err
} }
opts := options.Find() opts := options.Find()
opts.SetLimit(100) opts.SetLimit(1000)
targetDBCollection := CollectionMap[collection_name] targetDBCollection := CollectionMap[collection_name]
orList := bson.A{} orList := bson.A{}
andList := bson.A{} andList := bson.A{}

View File

@@ -1,10 +1,10 @@
package workflow_execution package workflow_execution
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"sync"
"time" "time"
"cloud.o-forge.io/core/oc-lib/logs" "cloud.o-forge.io/core/oc-lib/logs"
@@ -16,6 +16,7 @@ import (
"cloud.o-forge.io/core/oc-lib/tools" "cloud.o-forge.io/core/oc-lib/tools"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/robfig/cron" "github.com/robfig/cron"
"github.com/rs/zerolog"
) )
/* /*
@@ -54,6 +55,8 @@ func NewScheduler(start string, end string, durationInS float64, cron string) *W
} }
func (ws *WorkflowSchedule) CheckBooking(wfID string, request *tools.APIRequest) (bool, *workflow.Workflow, []*WorkflowExecution, []*booking.Booking, error) { func (ws *WorkflowSchedule) CheckBooking(wfID string, request *tools.APIRequest) (bool, *workflow.Workflow, []*WorkflowExecution, []*booking.Booking, error) {
l := logs.GetLogger().With().Str("SchedulerID", ws.UUID).Logger()
l.Debug().Msg("Checking booking")
if request.Caller == nil && request.Caller.URLS == nil && request.Caller.URLS[tools.BOOKING] == nil || request.Caller.URLS[tools.BOOKING][tools.GET] == "" { if request.Caller == nil && request.Caller.URLS == nil && request.Caller.URLS[tools.BOOKING] == nil || request.Caller.URLS[tools.BOOKING][tools.GET] == "" {
return false, nil, []*WorkflowExecution{}, []*booking.Booking{}, errors.New("no caller defined") return false, nil, []*WorkflowExecution{}, []*booking.Booking{}, errors.New("no caller defined")
} }
@@ -72,27 +75,69 @@ func (ws *WorkflowSchedule) CheckBooking(wfID string, request *tools.APIRequest)
if ws.End != nil && ws.Start.Add(time.Duration(longest)*time.Second).After(*ws.End) { if ws.End != nil && ws.Start.Add(time.Duration(longest)*time.Second).After(*ws.End) {
ws.Warning = "The workflow may be too long to be executed in the given time frame, we will try to book it anyway\n" ws.Warning = "The workflow may be too long to be executed in the given time frame, we will try to book it anyway\n"
} }
l.Debug().Msg("Getting executions")
execs, err := ws.getExecutions(wf) execs, err := ws.getExecutions(wf)
if err != nil { if err != nil {
return false, wf, []*WorkflowExecution{}, []*booking.Booking{}, err return false, wf, []*WorkflowExecution{}, []*booking.Booking{}, err
} }
bookings := []*booking.Booking{} bookings := []*booking.Booking{}
for _, exec := range execs { for i, exec := range execs {
l.Debug().Msg("looping throughs execs : " + string(i))
bookings = append(bookings, exec.Book(ws.UUID, wfID, priceds)...) bookings = append(bookings, exec.Book(ws.UUID, wfID, priceds)...)
}
errCh := make(chan error, len(bookings))
var m sync.Mutex
for _, b := range bookings { for _, b := range bookings {
go getBooking(l, b, request, wf, execs, bookings, errCh, &m)
}
for i := 0; i < len(bookings); i++ {
if err := <-errCh; err != nil {
return false, wf, execs, bookings, err
}
}
return true, wf, execs, bookings, nil
}
func getBooking(l zerolog.Logger, b *booking.Booking, request *tools.APIRequest, wf *workflow.Workflow, execs []*WorkflowExecution, bookings []*booking.Booking, errCh chan error, m *sync.Mutex) {
m.Lock()
c, err := getCallerCopy(request, errCh)
if err != nil {
errCh <- err
return
}
m.Unlock()
bl := l.With().Str("booking", b.UUID).Logger()
meth := request.Caller.URLS[tools.BOOKING][tools.GET] meth := request.Caller.URLS[tools.BOOKING][tools.GET]
meth = strings.ReplaceAll(meth, ":id", b.ResourceID) meth = strings.ReplaceAll(meth, ":id", b.ResourceID)
meth = strings.ReplaceAll(meth, ":start_date", b.ExpectedStartDate.Format("2006-01-02T15:04:05")) meth = strings.ReplaceAll(meth, ":start_date", b.ExpectedStartDate.Format("2006-01-02T15:04:05"))
meth = strings.ReplaceAll(meth, ":end_date", b.ExpectedEndDate.Format("2006-01-02T15:04:05")) meth = strings.ReplaceAll(meth, ":end_date", b.ExpectedEndDate.Format("2006-01-02T15:04:05"))
request.Caller.URLS[tools.BOOKING][tools.GET] = meth request.Caller.URLS[tools.BOOKING][tools.GET] = meth
_, err := (&peer.Peer{}).LaunchPeerExecution(b.DestPeerID, b.ResourceID, tools.BOOKING, tools.GET, nil, request.Caller) bl.Debug().Msg("Get booking " + b.UUID + " on " + b.DestPeerID)
_, err = (&peer.Peer{}).LaunchPeerExecution(b.DestPeerID, b.ResourceID, tools.BOOKING, tools.GET, nil, &c)
bl.Debug().Msg("Received response from Get booking " + b.UUID + " on " + b.DestPeerID)
if err != nil { if err != nil {
return false, wf, execs, bookings, err errCh <- err
} return
} }
errCh <- nil
} }
return true, wf, execs, bookings, nil
func getCallerCopy(request *tools.APIRequest, errCh chan error) (tools.HTTPCaller, error) {
var c tools.HTTPCaller
err := request.Caller.DeepCopy(c)
if err != nil {
errCh <- err
return tools.HTTPCaller{}, nil
}
c.URLS = request.Caller.URLS
return c, err
} }
func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*WorkflowSchedule, *workflow.Workflow, []*WorkflowExecution, error) { func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*WorkflowSchedule, *workflow.Workflow, []*WorkflowExecution, error) {
@@ -113,15 +158,20 @@ func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*
return ws, nil, executions, errors.New("could not book the workflow : " + fmt.Sprintf("%v", err)) return ws, nil, executions, errors.New("could not book the workflow : " + fmt.Sprintf("%v", err))
} }
ws.Workflow = wf ws.Workflow = wf
var errCh = make(chan error, len(bookings))
var m sync.Mutex
for _, booking := range bookings { for _, booking := range bookings {
l := logs.GetLogger() go ws.BookExecs(booking, request, errCh, &m)
l.Info().Msg("Booking on " + booking.DestPeerID) }
_, err := (&peer.Peer{}).LaunchPeerExecution(booking.DestPeerID, "",
tools.BOOKING, tools.POST, booking.Serialize(booking), request.Caller) for i := 0; i < len(bookings); i++ {
if err != nil { if err := <- errCh ; err != nil {
return ws, wf, executions, errors.New("could not launch the peer execution : " + fmt.Sprintf("%v", err)) return ws, wf, executions, errors.New("could not launch the peer execution : " + fmt.Sprintf("%v", err))
} }
} }
fmt.Println("Schedules") fmt.Println("Schedules")
for _, exec := range executions { for _, exec := range executions {
err := exec.PurgeDraft(request) err := exec.PurgeDraft(request)
@@ -135,6 +185,30 @@ func (ws *WorkflowSchedule) Schedules(wfID string, request *tools.APIRequest) (*
return ws, wf, executions, nil return ws, wf, executions, nil
} }
func (ws *WorkflowSchedule) BookExecs(booking *booking.Booking, request *tools.APIRequest, errCh chan error, m *sync.Mutex) {
m.Lock()
c, err := getCallerCopy(request, errCh)
if err != nil {
errCh <- err
return
}
m.Unlock()
l := logs.GetLogger().With().Str("SchedulerID", ws.UUID).Logger()
l.Debug().Msg("Booking " + booking.UUID + " on " + booking.DestPeerID)
_, err = (&peer.Peer{}).LaunchPeerExecution(booking.DestPeerID, "",
tools.BOOKING, tools.POST, booking.Serialize(booking), &c)
l.Debug().Msg("Received answer for booking " + booking.UUID + " on " + booking.DestPeerID)
if err != nil {
errCh <- err
return
}
errCh <- nil
}
/* /*
BOOKING IMPLIED TIME, not of subscription but of execution BOOKING IMPLIED TIME, not of subscription but of execution
so is processing time execution time applied on computes so is processing time execution time applied on computes
@@ -154,9 +228,6 @@ func (ws *WorkflowSchedule) getExecutions(workflow *workflow.Workflow) ([]*Workf
return workflows_executions, err return workflows_executions, err
} }
for _, date := range dates { for _, date := range dates {
fmt.Println("============")
fmt.Println("Date : " + fmt.Sprint(date))
fmt.Println("============")
obj := &WorkflowExecution{ obj := &WorkflowExecution{
AbstractObject: utils.AbstractObject{ AbstractObject: utils.AbstractObject{
UUID: uuid.New().String(), // set the uuid of the execution UUID: uuid.New().String(), // set the uuid of the execution
@@ -193,17 +264,8 @@ func (ws *WorkflowSchedule) getDates() ([]Schedule, error) {
if err != nil { if err != nil {
return schedule, errors.New("Bad cron message: " + err.Error()) return schedule, errors.New("Bad cron message: " + err.Error())
} }
toto, _ := json.MarshalIndent(sched,"","")
fmt.Println(string(toto))
s := sched.Next(ws.Start)
fmt.Println("s.IsZero() : " + fmt.Sprint(s.IsZero()) + "s.Before(*ws.End) : " + fmt.Sprint(s.Before(*ws.End)) )
tata, _ := json.MarshalIndent(s,"","")
fmt.Println("s = " + string(tata) + " et ws.End = " + fmt.Sprint(ws.End))
// loop through the cron schedule to set the executions // loop through the cron schedule to set the executions
for s := sched.Next(ws.Start); !s.IsZero() && s.Before(*ws.End); s = sched.Next(s) { for s := sched.Next(ws.Start); !s.IsZero() && s.Before(*ws.End); s = sched.Next(s) {
fmt.Println("next execution :" + fmt.Sprint(s))
e := s.Add(time.Duration(ws.DurationS) * time.Second) e := s.Add(time.Duration(ws.DurationS) * time.Second)
schedule = append(schedule, Schedule{ schedule = append(schedule, Schedule{
Start: s, Start: s,

View File

@@ -63,6 +63,16 @@ func NewHTTPCaller(urls map[DataType]map[METHOD]string) *HTTPCaller {
} }
} }
// Creates a copy of the current caller, in order to have parallelized executions without race condition
func (c* HTTPCaller) DeepCopy(dst HTTPCaller) error {
bytes, err := json.Marshal(c)
if err != nil {
return err
}
return json.Unmarshal(bytes, &dst)
}
// CallGet calls the GET method on the HTTP server // CallGet calls the GET method on the HTTP server
func (caller *HTTPCaller) CallGet(url string, subpath string, types ...string) ([]byte, error) { func (caller *HTTPCaller) CallGet(url string, subpath string, types ...string) ([]byte, error) {
req, err := http.NewRequest(http.MethodGet, url+subpath, bytes.NewBuffer([]byte(""))) req, err := http.NewRequest(http.MethodGet, url+subpath, bytes.NewBuffer([]byte("")))