code: func (handler *TaskHandler) taskStateChangesToSend() []api.TaskStateChange {
  	handler.lock.RLock()
  	defer handler.lock.RUnlock()
  
  	var events []api.TaskStateChange
  	for taskARN := range handler.tasksToContainerStates {
  		// An entry for the task in tasksToContainerStates means that there
  		// is at least 1 container event for that task that hasn't been sent
  		// to ECS (has been batched).
  		// Make sure that the engine's task state knows about this task (as a
  		// safety mechanism) and add it to the list of task state changes
  		// that need to be sent to ECS
  		if task, ok := handler.state.TaskByArn(taskARN); ok {
  			// We do not allow the ticker to submit container state updates for
  			// tasks that are STOPPED. This prevents the ticker's asynchronous
  			// updates from clobbering container states when the task
  			// transitions to STOPPED, since ECS does not allow updates to
  			// container states once the task has moved to STOPPED.
  			knownStatus := task.GetKnownStatus()
  			if knownStatus >= apitaskstatus.TaskStopped {
  				continue
  			}
  			event := api.TaskStateChange{
  				TaskARN: taskARN,
  				Status:  task.GetKnownStatus(),
  				Task:    task,
  			}
  			event.SetTaskTimestamps()
  
  			events = append(events, event)
  		}
  	}
  	return events
  }
docs: // taskStateChangesToSend gets a list task state changes for container events that
  // have been batched and not sent beyond the drainEventsFrequency threshold