// The executor calls this when it has finished running the runonce (be it success or failure) // stagerBBS will retry this repeatedly if it gets a StoreTimeout error (up to N seconds?) // This really really shouldn't fail. If it does, blog about it and walk away. If it failed in a // consistent way (i.e. key already exists), there's probably a flaw in our design. func (self *executorBBS) CompleteTask(task *models.Task, failed bool, failureReason string, result string) error { originalValue := task.ToJSON() task.UpdatedAt = self.timeProvider.Time().UnixNano() task.State = models.TaskStateCompleted task.Failed = failed task.FailureReason = failureReason task.Result = result return retryIndefinitelyOnStoreTimeout(func() error { err := self.store.CompareAndSwap(storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: originalValue, }, storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: task.ToJSON(), }) if err != nil { return err } self.kicker.Complete(task) return nil }) }
func (s *stagerBBS) ResolvingTask(task *models.Task) error { originalValue := task.ToJSON() task.UpdatedAt = s.timeProvider.Time().UnixNano() task.State = models.TaskStateResolving return retryIndefinitelyOnStoreTimeout(func() error { return s.store.CompareAndSwap(storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: originalValue, }, storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: task.ToJSON(), }) }) }
// The executor calls this when it is about to run the runonce in the claimed container // stagerBBS will retry this repeatedly if it gets a StoreTimeout error (up to N seconds?) // If this fails, the executor should assume that someone else is running and should clean up and bail func (self *executorBBS) StartTask(task *models.Task, containerHandle string) error { originalValue := task.ToJSON() task.UpdatedAt = self.timeProvider.Time().UnixNano() task.State = models.TaskStateRunning task.ContainerHandle = containerHandle return retryIndefinitelyOnStoreTimeout(func() error { return self.store.CompareAndSwap(storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: originalValue, }, storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: task.ToJSON(), }) }) }
// The executor calls this when it wants to claim a runonce // stagerBBS will retry this repeatedly if it gets a StoreTimeout error (up to N seconds?) // If this fails, the executor should assume that someone else is handling the claim and should bail func (self *executorBBS) ClaimTask(task *models.Task, executorID string) error { originalValue := task.ToJSON() task.UpdatedAt = self.timeProvider.Time().UnixNano() task.State = models.TaskStateClaimed task.ExecutorID = executorID return retryIndefinitelyOnStoreTimeout(func() error { return self.store.CompareAndSwap(storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: originalValue, }, storeadapter.StoreNode{ Key: taskSchemaPath(task), Value: task.ToJSON(), }) }) }
// The stager calls this when it wants to desire a payload // stagerBBS will retry this repeatedly if it gets a StoreTimeout error (up to N seconds?) // If this fails, the stager should bail and run its "this-failed-to-stage" routine func (s *stagerBBS) DesireTask(task *models.Task) error { return retryIndefinitelyOnStoreTimeout(func() error { if task.CreatedAt == 0 { task.CreatedAt = s.timeProvider.Time().UnixNano() } task.UpdatedAt = s.timeProvider.Time().UnixNano() task.State = models.TaskStatePending err := s.store.SetMulti([]storeadapter.StoreNode{ { Key: taskSchemaPath(task), Value: task.ToJSON(), }, }) if err != nil { return err } s.kicker.Desire(task) return nil }) }