// startACSSession starts a session with ACS. It adds request handlers for various // kinds of messages expected from ACS. It returns on server disconnection or when // the context is cancelled func startACSSession(ctx context.Context, client wsclient.ClientServer, timer ttime.Timer, args StartSessionArguments, backoff *utils.SimpleBackoff, acsSessionState sessionState) error { // Any message from the server resets the disconnect timeout client.SetAnyRequestHandler(anyMessageHandler(timer)) cfg := args.Config refreshCredsHandler := newRefreshCredentialsHandler(ctx, cfg.Cluster, args.ContainerInstanceArn, client, args.CredentialsManager, args.TaskEngine) defer refreshCredsHandler.clearAcks() refreshCredsHandler.start() client.AddRequestHandler(refreshCredsHandler.handlerFunc()) // Add request handler for handling payload messages from ACS payloadHandler := newPayloadRequestHandler(ctx, args.TaskEngine, args.ECSClient, cfg.Cluster, args.ContainerInstanceArn, client, args.StateManager, refreshCredsHandler, args.CredentialsManager) // Clear the acks channel on return because acks of messageids don't have any value across sessions defer payloadHandler.clearAcks() payloadHandler.start() client.AddRequestHandler(payloadHandler.handlerFunc()) // Ignore heartbeat messages; anyMessageHandler gets 'em client.AddRequestHandler(func(*ecsacs.HeartbeatMessage) {}) updater.AddAgentUpdateHandlers(client, cfg, args.StateManager, args.TaskEngine) err := client.Connect() if err != nil { seelog.Errorf("Error connecting to ACS: %v", err) return err } acsSessionState.connectedToACS() backoffResetTimer := args.time().AfterFunc(utils.AddJitter(args.heartbeatTimeout(), args.heartbeatJitter()), func() { // If we do not have an error connecting and remain connected for at // least 5 or so minutes, reset the backoff. This prevents disconnect // errors that only happen infrequently from damaging the // reconnectability as significantly. backoff.Reset() }) defer backoffResetTimer.Stop() serveErr := make(chan error, 1) go func() { serveErr <- client.Serve() }() for { select { case <-ctx.Done(): // Stop receiving and sending messages from and to ACS when // the context received from the main function is canceled payloadHandler.stop() refreshCredsHandler.stop() return ctx.Err() case err := <-serveErr: // Stop receiving and sending messages from and to ACS when // client.Serve returns an error. This can happen when the // the connection is closed by ACS or the agent payloadHandler.stop() refreshCredsHandler.stop() return err } } }