// FinalSave should be called immediately before exiting, and only before
// exiting, in order to flush tasks to disk. It waits a short timeout for state
// to settle if necessary. If unable to reach a steady-state and save within
// this short timeout, it returns an error
func FinalSave(saver statemanager.Saver, taskEngine engine.TaskEngine) error {
	engineDisabled := make(chan error)

	disableTimer := time.AfterFunc(engineDisableTimeout, func() {
		engineDisabled <- errors.New("Timed out waiting for TaskEngine to settle")
	})

	go func() {
		log.Debug("Shutting down task engine")
		taskEngine.Disable()
		disableTimer.Stop()
		engineDisabled <- nil
	}()

	disableErr := <-engineDisabled

	stateSaved := make(chan error)
	saveTimer := time.AfterFunc(finalSaveTimeout, func() {
		stateSaved <- errors.New("Timed out trying to save to disk")
	})
	go func() {
		log.Debug("Saving state before shutting down")
		stateSaved <- saver.ForceSave()
		saveTimer.Stop()
	}()

	saveErr := <-stateSaved

	if disableErr != nil || saveErr != nil {
		return utils.NewMultiError(disableErr, saveErr)
	}
	return nil
}
Ejemplo n.º 2
0
// handlePayloadMessage attempts to add each task to the taskengine and, if it can, acks the request.
func handlePayloadMessage(responseChan chan<- string, cluster, containerInstanceArn string, payload *ecsacs.PayloadMessage, taskEngine engine.TaskEngine, client api.ECSClient, saver statemanager.Saver) {
	if payload.MessageId == nil {
		log.Crit("Recieved a payload with no message id", "payload", payload)
		return
	}
	allTasksHandled := addPayloadTasks(client, cluster, containerInstanceArn, payload, taskEngine)
	// save the state of tasks we know about after passing them to the task engine
	err := saver.Save()
	if err != nil {
		log.Error("Error saving state for payload message!", "err", err, "messageId", *payload.MessageId)
		// Don't ack; maybe we can save it in the future.
		return
	}
	if allTasksHandled {
		go func() {
			// Throw the ack in async; it doesn't really matter all that much and this is blocking handling more tasks.
			responseChan <- *payload.MessageId
		}()
		// Record the sequence number as well
		if payload.SeqNum != nil {
			SequenceNumber.Set(*payload.SeqNum)
		}
	}
}