code: func (handler *TaskHandler) submitTaskEvents(taskEvents *taskSendableEvents, client api.ECSClient, taskARN string) {
  	defer metrics.MetricsEngineGlobal.RecordECSClientMetric("SUBMIT_TASK_EVENTS")()
  	defer handler.removeTaskEvents(taskARN)
  
  	backoff := retry.NewExponentialBackoff(submitStateBackoffMin, submitStateBackoffMax,
  		submitStateBackoffJitterMultiple, submitStateBackoffMultiple)
  
  	// Mirror events.sending, but without the need to lock since this is local
  	// to our goroutine
  	done := false
  	// TODO: wire in the context here. Else, we have go routine leaks in tests
  	for !done {
  		// If we looped back up here, we successfully submitted an event, but
  		// we haven't emptied the list so we should keep submitting
  		backoff.Reset()
  		retry.RetryWithBackoff(backoff, func() error {
  			// Lock and unlock within this function, allowing the list to be added
  			// to while we're not actively sending an event
  			seelog.Debug("TaskHandler: Waiting on semaphore to send events...")
  			handler.submitSemaphore.Wait()
  			defer handler.submitSemaphore.Post()
  
  			var err error
  			done, err = taskEvents.submitFirstEvent(handler, backoff)
  			return err
  		})
  	}
  }
docs: // Continuously retries sending an event until it succeeds, sleeping between each
  // attempt