Skip to content

Commit 1f3d089

Browse files
joe4devclaude
andcommitted
chore(init): close HTTP response bodies and minor cleanups
- Close response bodies in SendStatus/SendLogs/SendResult so idle connections are released instead of leaked. - Use errors.New instead of fmt.Errorf with no format arguments. - Document the single-invoke assumption behind the unsynchronized initStart/warmStart fields. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 557bc77 commit 1f3d089

2 files changed

Lines changed: 21 additions & 8 deletions

File tree

cmd/localstack/custom_interop.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ type CustomInteropServer struct {
2828
localStackAdapter *LocalStackAdapter
2929
port string
3030
upstreamEndpoint string
31-
initStart time.Time
32-
warmStart bool
31+
// initStart is set once in Init() and warmStart is flipped on the first invoke.
32+
// Both are accessed only from the single sequential init -> invoke flow (the RIE
33+
// processes one invocation at a time), so they need no additional synchronization.
34+
initStart time.Time
35+
warmStart bool
3336
}
3437

3538
type LocalStackAdapter struct {
@@ -46,10 +49,11 @@ const (
4649

4750
func (l *LocalStackAdapter) SendStatus(status LocalStackStatus, payload []byte) error {
4851
statusUrl := fmt.Sprintf("%s/status/%s/%s", l.UpstreamEndpoint, l.RuntimeId, status)
49-
_, err := http.Post(statusUrl, "application/json", bytes.NewReader(payload))
52+
resp, err := http.Post(statusUrl, "application/json", bytes.NewReader(payload))
5053
if err != nil {
5154
return err
5255
}
56+
defer resp.Body.Close()
5357
return nil
5458
}
5559

@@ -59,8 +63,12 @@ func (l *LocalStackAdapter) SendLogs(invokeId string, logs lsapi.LogResponse) er
5963
if err != nil {
6064
return err
6165
}
62-
_, err = http.Post(l.UpstreamEndpoint+"/invocations/"+invokeId+"/logs", "application/json", bytes.NewReader(serialized))
63-
return err
66+
resp, err := http.Post(l.UpstreamEndpoint+"/invocations/"+invokeId+"/logs", "application/json", bytes.NewReader(serialized))
67+
if err != nil {
68+
return err
69+
}
70+
defer resp.Body.Close()
71+
return nil
6472
}
6573

6674
// SendResult posts the invocation result body to LocalStack.
@@ -80,8 +88,12 @@ func (l *LocalStackAdapter) SendResult(invokeId string, body []byte, isError boo
8088
} else {
8189
log.Infoln("Sending to /response")
8290
}
83-
_, err := http.Post(l.UpstreamEndpoint+endpoint, "application/json", bytes.NewReader(body))
84-
return err
91+
resp, err := http.Post(l.UpstreamEndpoint+endpoint, "application/json", bytes.NewReader(body))
92+
if err != nil {
93+
return err
94+
}
95+
defer resp.Body.Close()
96+
return nil
8597
}
8698

8799
func NewCustomInteropServer(lsOpts *LsOpts, delegate interop.Server, logCollector *LogCollector) (server *CustomInteropServer) {

cmd/localstack/supervisor.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"strings"
78
"sync/atomic"
@@ -78,7 +79,7 @@ func (ls *LocalStackSupervisor) loop(ctx context.Context) {
7879

7980
faultData := interop.FaultData{
8081
RequestID: interop.RequestID(uuid.NewString()),
81-
ErrorMessage: fmt.Errorf("Runtime exited without providing a reason"),
82+
ErrorMessage: errors.New("Runtime exited without providing a reason"),
8283
ErrorType: fatalerror.RuntimeExit,
8384
}
8485
if !termination.Success() {

0 commit comments

Comments
 (0)