Skip to content

Commit 57ad85c

Browse files
authored
Update workflows (#487)
* Update workflows * fix version
1 parent 3dedc32 commit 57ad85c

File tree

7 files changed

+64
-10
lines changed

7 files changed

+64
-10
lines changed

Diff for: .github/workflows/lint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ jobs:
1818

1919
- name: golangci-golint
2020
run: |
21-
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.48.0
21+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v1.52.1
2222
./bin/golangci-lint run -v ./...
2323

Diff for: .github/workflows/tests.yml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
strategy:
1111
matrix:
1212
go:
13+
- "1.20"
1314
- "1.19"
1415
- "1.18"
1516
- "1.17"

Diff for: .golangci.yml

+1-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@ linters:
33
enable:
44
- gofmt
55
- errcheck
6-
- deadcode
76
- gosimple
87
- govet
98
- ineffassign
109
- staticcheck
11-
- structcheck
1210
- typecheck
1311
- unused
14-
- varcheck
1512
- stylecheck
1613

1714
run:
@@ -21,6 +18,6 @@ run:
2118

2219
linters-settings:
2320
stylecheck:
24-
go: "1.17"
21+
go: "1.20"
2522
checks: ["all"]
2623
initialisms: ["AWS", "ARN", "IAM", "MQTT", "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS"]

Diff for: lambda/handler.go

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type handlerOptions struct {
2828
jsonResponseIndentValue string
2929
enableSIGTERM bool
3030
sigtermCallbacks []func()
31+
setupFuncs []func() error
3132
}
3233

3334
type Option func(*handlerOptions)
@@ -102,6 +103,15 @@ func WithEnableSIGTERM(callbacks ...func()) Option {
102103
})
103104
}
104105

106+
// WithSetup enables capturing of errors or panics that occur before the function is ready to handle invokes.
107+
// The provided functions will be run a single time, in order, before the runtime reports itself ready to recieve invokes.
108+
// If any of the provided functions returns an error, or panics, the error will be serialized and reported to the Runtime API.
109+
func WithSetup(funcs ...func() error) Option {
110+
return Option(func(h *handlerOptions) {
111+
h.setupFuncs = append(h.setupFuncs, funcs...)
112+
})
113+
}
114+
105115
// handlerTakesContext returns whether the handler takes a context.Context as its first argument.
106116
func handlerTakesContext(handler reflect.Type) (bool, error) {
107117
switch handler.NumIn() {

Diff for: lambda/invoke_loop.go

+31
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ func unixMS(ms int64) time.Time {
3131
func startRuntimeAPILoop(api string, handler Handler) error {
3232
client := newRuntimeAPIClient(api)
3333
h := newHandler(handler)
34+
35+
if err := handleSetup(client, h); err != nil {
36+
return err
37+
}
3438
for {
3539
invoke, err := client.next()
3640
if err != nil {
@@ -42,6 +46,21 @@ func startRuntimeAPILoop(api string, handler Handler) error {
4246
}
4347
}
4448

49+
// handleSetup returns an error if any of the handler's optional setup functions return and error or panic
50+
func handleSetup(client *runtimeAPIClient, handler *handlerOptions) error {
51+
for _, setup := range handler.setupFuncs {
52+
if setupErr := callSetupFunc(setup); setupErr != nil {
53+
errorPayload := safeMarshal(setupErr)
54+
log.Printf("%s", errorPayload)
55+
if err := client.initError(bytes.NewReader(errorPayload), contentTypeJSON); err != nil {
56+
return fmt.Errorf("unexpected error occurred when sending the setup error to the API: %v", err)
57+
}
58+
return fmt.Errorf("setting up the handler function resulted in an error, the process should exit")
59+
}
60+
}
61+
return nil
62+
}
63+
4564
// handleInvoke returns an error if the function panics, or some other non-recoverable error occurred
4665
func handleInvoke(invoke *invoke, handler *handlerOptions) error {
4766
// set the deadline
@@ -110,6 +129,18 @@ func reportFailure(invoke *invoke, invokeErr *messages.InvokeResponse_Error) err
110129
return nil
111130
}
112131

132+
func callSetupFunc(f func() error) (setupErr *messages.InvokeResponse_Error) {
133+
defer func() {
134+
if err := recover(); err != nil {
135+
setupErr = lambdaPanicResponse(err)
136+
}
137+
}()
138+
if err := f(); err != nil {
139+
return lambdaErrorResponse(err)
140+
}
141+
return nil
142+
}
143+
113144
func callBytesHandlerFunc(ctx context.Context, payload []byte, handler handlerFunc) (response io.Reader, invokeErr *messages.InvokeResponse_Error) {
114145
defer func() {
115146
if err := recover(); err != nil {

Diff for: lambda/rpc_function.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,19 @@ func init() {
3333
}
3434

3535
func startFunctionRPC(port string, handler Handler) error {
36+
rpcFunction := NewFunction(handler)
37+
if len(rpcFunction.handler.setupFuncs) > 0 {
38+
runtimeAPIClient := newRuntimeAPIClient(os.Getenv("AWS_LAMBDA_RUNTIME_API"))
39+
if err := handleSetup(runtimeAPIClient, rpcFunction.handler); err != nil {
40+
return err
41+
}
42+
}
43+
3644
lis, err := net.Listen("tcp", "localhost:"+port)
3745
if err != nil {
3846
log.Fatal(err)
3947
}
40-
err = rpc.Register(NewFunction(handler))
48+
err = rpc.Register(rpcFunction)
4149
if err != nil {
4250
log.Fatal("failed to register handler function")
4351
}

Diff for: lambda/runtime_api_client.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,18 @@ func newRuntimeAPIClient(address string) *runtimeAPIClient {
3737
client := &http.Client{
3838
Timeout: 0, // connections to the runtime API are never expected to time out
3939
}
40-
endpoint := "http://" + address + "/" + apiVersion + "/runtime/invocation/"
40+
endpoint := "http://" + address + "/" + apiVersion + "/runtime"
4141
userAgent := "aws-lambda-go/" + runtime.Version()
4242
return &runtimeAPIClient{endpoint, userAgent, client, bytes.NewBuffer(nil)}
4343
}
4444

45+
// initError connects to the Runtime API and reports that a failure occured during initialization.
46+
// Note: After calling this function, the caller should call os.Exit()
47+
func (c *runtimeAPIClient) initError(body io.Reader, contentType string) error {
48+
url := c.baseURL + "/init/error"
49+
return c.post(url, body, contentType)
50+
}
51+
4552
type invoke struct {
4653
id string
4754
payload []byte
@@ -53,7 +60,7 @@ type invoke struct {
5360
// Notes:
5461
// - An invoke is not complete until next() is called again!
5562
func (i *invoke) success(body io.Reader, contentType string) error {
56-
url := i.client.baseURL + i.id + "/response"
63+
url := i.client.baseURL + "/invocation/" + i.id + "/response"
5764
return i.client.post(url, body, contentType)
5865
}
5966

@@ -63,14 +70,14 @@ func (i *invoke) success(body io.Reader, contentType string) error {
6370
// - A Lambda Function continues to be re-used for future invokes even after a failure.
6471
// If the error is fatal (panic, unrecoverable state), exit the process immediately after calling failure()
6572
func (i *invoke) failure(body io.Reader, contentType string) error {
66-
url := i.client.baseURL + i.id + "/error"
73+
url := i.client.baseURL + "/invocation/" + i.id + "/error"
6774
return i.client.post(url, body, contentType)
6875
}
6976

7077
// next connects to the Runtime API and waits for a new invoke Request to be available.
7178
// Note: After a call to Done() or Error() has been made, a call to next() will complete the in-flight invoke.
7279
func (c *runtimeAPIClient) next() (*invoke, error) {
73-
url := c.baseURL + "next"
80+
url := c.baseURL + "/invocation/next"
7481
req, err := http.NewRequest(http.MethodGet, url, nil)
7582
if err != nil {
7683
return nil, fmt.Errorf("failed to construct GET request to %s: %v", url, err)

0 commit comments

Comments
 (0)