Skip to content

Commit 64e4ef6

Browse files
committed
Refactor ACS heartbeat message handling
1 parent 2b743fb commit 64e4ef6

File tree

13 files changed

+202
-101
lines changed

13 files changed

+202
-101
lines changed

agent/acs/handler/acs_handler.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/aws/amazon-ecs-agent/agent/eventhandler"
3535
"github.com/aws/amazon-ecs-agent/agent/eventstream"
3636
"github.com/aws/amazon-ecs-agent/agent/version"
37+
acssession "github.com/aws/amazon-ecs-agent/ecs-agent/acs/session"
3738
rolecredentials "github.com/aws/amazon-ecs-agent/ecs-agent/credentials"
3839
"github.com/aws/amazon-ecs-agent/ecs-agent/doctor"
3940
"github.com/aws/amazon-ecs-agent/ecs-agent/utils/retry"
@@ -321,7 +322,12 @@ func (acsSession *session) startACSSession(client wsclient.ClientServer) error {
321322

322323
client.AddRequestHandler(payloadHandler.handlerFunc())
323324

324-
client.AddRequestHandler(HeartbeatHandlerFunc(client, acsSession.doctor))
325+
responseSender := func(response interface{}) error {
326+
return client.MakeRequest(response)
327+
}
328+
329+
heartbeatResponder := acssession.NewHeartbeatResponder(acsSession.doctor, responseSender)
330+
client.AddRequestHandler(heartbeatResponder.HandlerFunc())
325331

326332
updater.AddAgentUpdateHandlers(client, cfg, acsSession.state, acsSession.dataClient, acsSession.taskEngine)
327333

agent/acs/handler/heartbeat_handler.go

-50
This file was deleted.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/acs/session/heartbeat_responder.go

+71
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/acs/session/session.go

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/logger/field/constants.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/wsclient/client.go

-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

agent/vendor/github.com/aws/amazon-ecs-agent/ecs-agent/wsclient/mock/client.go

-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package session
15+
16+
import (
17+
"github.com/aws/amazon-ecs-agent/ecs-agent/acs/model/ecsacs"
18+
"github.com/aws/amazon-ecs-agent/ecs-agent/doctor"
19+
"github.com/aws/amazon-ecs-agent/ecs-agent/logger"
20+
"github.com/aws/amazon-ecs-agent/ecs-agent/logger/field"
21+
"github.com/aws/amazon-ecs-agent/ecs-agent/wsclient"
22+
23+
"github.com/aws/aws-sdk-go/aws"
24+
)
25+
26+
// heartbeatResponder implements the wsclient.RequestResponder interface for responding
27+
// to ecsacs.HeartbeatMessage type.
28+
type heartbeatResponder struct {
29+
doctor *doctor.Doctor
30+
respond wsclient.RespondFunc
31+
}
32+
33+
// NewHeartbeatResponder returns an instance of the heartbeatResponder struct.
34+
func NewHeartbeatResponder(doctor *doctor.Doctor, responseSender wsclient.RespondFunc) wsclient.RequestResponder {
35+
r := &heartbeatResponder{
36+
doctor: doctor,
37+
}
38+
r.respond = ResponseToACSSender(r.Name(), responseSender)
39+
return r
40+
}
41+
42+
func (*heartbeatResponder) Name() string {
43+
return "heartbeat message responder"
44+
}
45+
46+
func (r *heartbeatResponder) HandlerFunc() wsclient.RequestHandler {
47+
return r.processHeartbeatMessage
48+
}
49+
50+
// processHeartbeatMessage processes an ACS heartbeat message.
51+
// This function is meant to be called from the ACS dispatcher and as such
52+
// should not block in any way to prevent starvation of the message handler.
53+
func (r *heartbeatResponder) processHeartbeatMessage(message *ecsacs.HeartbeatMessage) {
54+
// Agent will run container instance healthchecks. They are triggered by ACS heartbeat.
55+
// Results of healthchecks will be sent on to TACS.
56+
go r.doctor.RunHealthchecks()
57+
58+
// Agent will send simple ack
59+
ack := &ecsacs.HeartbeatAckRequest{
60+
MessageId: message.MessageId,
61+
}
62+
go func() {
63+
err := r.respond(ack)
64+
if err != nil {
65+
logger.Warn("Error acknowledging server heartbeat", logger.Fields{
66+
field.MessageID: aws.StringValue(ack.MessageId),
67+
field.Error: err,
68+
})
69+
}
70+
}()
71+
}

agent/acs/handler/heartbeat_handler_test.go renamed to ecs-agent/acs/session/heartbeat_responder_test.go

+11-12
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,17 @@
1414
// express or implied. See the License for the specific language governing
1515
// permissions and limitations under the License.
1616

17-
package handler
17+
package session
1818

1919
import (
2020
"testing"
2121

22-
"github.com/aws/amazon-ecs-agent/ecs-agent/acs/model/ecsacs"
23-
"github.com/aws/amazon-ecs-agent/ecs-agent/doctor"
24-
mock_wsclient "github.com/aws/amazon-ecs-agent/ecs-agent/wsclient/mock"
25-
2622
"github.com/aws/aws-sdk-go/aws"
2723
"github.com/golang/mock/gomock"
2824
"github.com/stretchr/testify/require"
25+
26+
"github.com/aws/amazon-ecs-agent/ecs-agent/acs/model/ecsacs"
27+
"github.com/aws/amazon-ecs-agent/ecs-agent/doctor"
2928
)
3029

3130
const (
@@ -87,16 +86,16 @@ func validateHeartbeatAck(t *testing.T, heartbeatReceived *ecsacs.HeartbeatMessa
8786

8887
ackSent := make(chan *ecsacs.HeartbeatAckRequest)
8988

90-
mockWsClient := mock_wsclient.NewMockClientServer(ctrl)
91-
mockWsClient.EXPECT().MakeRequest(gomock.Any()).Do(func(message *ecsacs.HeartbeatAckRequest) {
92-
ackSent <- message
93-
close(ackSent)
94-
}).Times(1)
95-
9689
emptyHealthchecksList := []doctor.Healthcheck{}
9790
emptyDoctor, _ := doctor.NewDoctor(emptyHealthchecksList, "testCluster", "this:is:an:instance:arn")
9891

99-
handleSingleHeartbeatMessage(mockWsClient, emptyDoctor, heartbeatReceived)
92+
testResponseSender := func(response interface{}) error {
93+
resp := response.(*ecsacs.HeartbeatAckRequest)
94+
ackSent <- resp
95+
return nil
96+
}
97+
testHeartbeatResponder := NewHeartbeatResponder(emptyDoctor, testResponseSender)
98+
testHeartbeatResponder.(*heartbeatResponder).processHeartbeatMessage(heartbeatReceived)
10099

101100
// wait till we send an
102101
heartbeatAckSent := <-ackSent

ecs-agent/acs/session/session.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package session
2+
3+
import (
4+
"github.com/aws/amazon-ecs-agent/ecs-agent/logger"
5+
"github.com/aws/amazon-ecs-agent/ecs-agent/wsclient"
6+
)
7+
8+
// ResponseToACSSender returns a wsclient.RespondFunc that a responder can invoke in response to receiving and
9+
// processing specific websocket request messages from ACS. The returned wsclient.RespondFunc:
10+
// 1. logs the response to be sent, as well as the name of the invoking responder
11+
// 2. sends the response request to ACS
12+
func ResponseToACSSender(responderName string, responseSender wsclient.RespondFunc) wsclient.RespondFunc {
13+
return func(response interface{}) error {
14+
logger.Debug("Sending response to ACS", logger.Fields{
15+
"Name": responderName,
16+
"Response": response,
17+
})
18+
return responseSender(response)
19+
}
20+
}

ecs-agent/logger/field/constants.go

+1
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ const (
4949
ContainerImage = "containerImage"
5050
ContainerExitCode = "containerExitCode"
5151
TMDSEndpointContainerID = "tmdsEndpointContainerID"
52+
MessageID = "messageID"
5253
)

ecs-agent/wsclient/client.go

-7
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,6 @@ type RequestHandler interface{}
9999
// respond func(interface{}) error
100100
// dispatcher actor.Dispatcher
101101
// }
102-
// func(d *payloadmessagedispatcher) RegisterResponder(respond func(interface{}) error) error {
103-
// d.respond = respond
104-
// return nil
105-
// }
106102
// func(d *payloadmessagedispatcher) HandlerFunc() RequestHandler {
107103
// return func(payload *ecsacs.PayloadMessage) {
108104
// message := &actor.DispatcherMessage{
@@ -118,9 +114,6 @@ type RequestHandler interface{}
118114
type RequestResponder interface {
119115
// Name returns the name of the responder. This is used mostly for logging.
120116
Name() string
121-
// RegisterResponder registers a function that can be invoked in response
122-
// to receiving and processing a websocket request message.
123-
RegisterResponder(RespondFunc)
124117
// HandlerFunc returns the RequestHandler callback for a particular
125118
// websocket request message type.
126119
HandlerFunc() RequestHandler

ecs-agent/wsclient/mock/client.go

-12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)