// This custom unmarshaller is needed because the json sent to us as a string // rather than a fully typed object. We support both formats in the hopes that // one day everything will be fully typed // Note: the `json:",string"` tag DOES NOT apply here; it DOES NOT work with // struct types, only ints/floats/etc. We're basically doing that though // We also intentionally fail if there are any keys we were unable to unmarshal // into our struct func (overrides *ContainerOverrides) UnmarshalJSON(b []byte) error { regular := ContainerOverridesCopy{} // Try to do it the strongly typed way first err := json.Unmarshal(b, ®ular) if err == nil { err = utils.CompleteJsonUnmarshal(b, regular) if err == nil { *overrides = ContainerOverrides(regular) return nil } err = utils.NewMultiError(errors.New("Error unmarshalling ContainerOverrides"), err) } // Now the stringly typed way var str string err2 := json.Unmarshal(b, &str) if err2 != nil { return utils.NewMultiError(errors.New("Could not unmarshal ContainerOverrides into either an object or string respectively"), err, err2) } // We have a string, let's try to unmarshal that into a typed object err3 := json.Unmarshal([]byte(str), ®ular) if err3 == nil { err3 = utils.CompleteJsonUnmarshal([]byte(str), regular) if err3 == nil { *overrides = ContainerOverrides(regular) return nil } else { err3 = utils.NewMultiError(errors.New("Error unmarshalling ContainerOverrides"), err3) } } return utils.NewMultiError(errors.New("Could not unmarshal ContainerOverrides in any supported way"), err, err2, err3) }
// 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 }