func (h *handler) runAgent(ctx context.Context) uint32 {
	agentCtx, cancel := context.WithCancel(ctx)
	indicator := newTermHandlerIndicator()

	terminationHandler := func(saver statemanager.Saver, taskEngine engine.TaskEngine) {
		// We're using a custom indicator to record that the handler is scheduled to be executed (has been invoked) and
		// to determine whether it should run (we skip when the agent engine has already exited).  After recording to
		// the indicator that the handler has been invoked, we wait on the context.  When we wake up, we determine
		// whether to execute or not based on whether the agent is still running.
		defer indicator.finish()
		indicator.setInvoked()
		<-agentCtx.Done()
		if !indicator.isAgentRunning() {
			return
		}

		seelog.Info("Termination handler received signal to stop")
		err := sighandlers.FinalSave(saver, taskEngine)
		if err != nil {
			seelog.Criticalf("Error saving state before final shutdown: %v", err)
		}
	}
	h.ecsAgent.setTerminationHandler(terminationHandler)

	go func() {
		defer cancel()
		exitCode := h.ecsAgent.start() // should block forever, unless there is an error

		if exitCode == exitcodes.ExitTerminal {
			seelog.Critical("Terminal exit code received from agent.  Windows SCM will not restart the AmazonECS service.")
			// We override the exit code to 0 here so that Windows does not treat this as a restartable failure even
			// when "sc.exe failureflag" is set.
			exitCode = 0
		}

		indicator.agentStopped(exitCode)
	}()

	sleepCtx(agentCtx, time.Minute) // give the agent a minute to start and invoke terminationHandler

	// wait for the termination handler to run.  Once the termination handler runs, we can safely exit.  If the agent
	// exits by itself, the termination handler doesn't need to do anything and skips.  If the agent exits before the
	// termination handler is invoked, we can exit immediately.
	return indicator.wait()
}
func (h *handler) runAgent(ctx context.Context) uint32 {
	agentCtx, cancel := context.WithCancel(ctx)
	indicator := newTermHandlerIndicator()

	terminationHandler := func(saver statemanager.Saver, taskEngine engine.TaskEngine) {
		// We're using a custom indicator to record that the handler is scheduled to be executed (has been invoked) and
		// to determine whether it should run (we skip when the agent engine has already exited).  After recording to
		// the indicator that the handler has been invoked, we wait on the context.  When we wake up, we determine
		// whether to execute or not based on whether the agent is still running.
		defer indicator.finish()
		indicator.setInvoked()
		<-agentCtx.Done()
		if !indicator.isAgentRunning() {
			return
		}

		seelog.Info("Termination handler received signal to stop")
		err := sighandlers.FinalSave(saver, taskEngine)
		if err != nil {
			seelog.Criticalf("Error saving state before final shutdown: %v", err)
		}
	}
	h.ecsAgent.setTerminationHandler(terminationHandler)

	go func() {
		defer cancel()
		exitCode := h.ecsAgent.start() // should block forever, unless there is an error

		if exitCode == exitcodes.ExitTerminal {
			seelog.Critical("Terminal exit code received from agent.  Windows SCM will not restart the AmazonECS service.")
			// We override the exit code to 0 here so that Windows does not treat this as a restartable failure even
			// when "sc.exe failureflag" is set.
			exitCode = 0
		}

		indicator.agentStopped(exitCode)
	}()

	sleepCtx(agentCtx, time.Minute) // give the agent a minute to start and invoke terminationHandler

	// wait for the termination handler to run.  Once the termination handler runs, we can safely exit.  If the agent
	// exits by itself, the termination handler doesn't need to do anything and skips.  If the agent exits before the
	// termination handler is invoked, we can exit immediately.
	return indicator.wait()
}
// runAgent runs the ECS agent inside a goroutine and waits to be told to exit.