Skip to content

Commit

Permalink
🐛 Avoid mutex deadlock when retrying
Browse files Browse the repository at this point in the history
  • Loading branch information
elgohr committed Dec 8, 2023
1 parent 8011787 commit f9358f5
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 28 deletions.
40 changes: 18 additions & 22 deletions localstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,25 +387,25 @@ func (i *Instance) mapPorts(ctx context.Context, services []Service, containerId
time.Sleep(300 * time.Millisecond)
return i.mapPorts(ctx, services, containerId, try+1)
}
i.portMappingMutex.Lock()
defer i.portMappingMutex.Unlock()
i.portMapping[FixedPort] = "localhost:" + bindings[0].HostPort
i.savePortMappings(map[Service]string{
FixedPort: "localhost:" + bindings[0].HostPort,
})
} else {
hasFilteredServices := len(services) > 0
i.portMappingMutex.Lock()
defer i.portMappingMutex.Unlock()
newMapping := make(map[Service]string, len(AvailableServices))
for service := range AvailableServices {
bindings := ports[nat.Port(service.Port)]
if len(bindings) == 0 {
time.Sleep(300 * time.Millisecond)
return i.mapPorts(ctx, services, containerId, try+1)
}
if hasFilteredServices && containsService(services, service) {
i.portMapping[service] = "localhost:" + bindings[0].HostPort
newMapping[service] = "localhost:" + bindings[0].HostPort
} else if !hasFilteredServices {
i.portMapping[service] = "localhost:" + bindings[0].HostPort
newMapping[service] = "localhost:" + bindings[0].HostPort
}
}
i.savePortMappings(newMapping)
}
return nil
}
Expand All @@ -432,7 +432,7 @@ func (i *Instance) waitToBeAvailable(ctx context.Context) error {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
if err := i.isRunning(ctx, 0); err != nil {
if err := i.isRunning(ctx); err != nil {
return err
}
if err := i.checkAvailable(ctx); err != nil {
Expand All @@ -445,21 +445,13 @@ func (i *Instance) waitToBeAvailable(ctx context.Context) error {
}
}

func (i *Instance) isRunning(ctx context.Context, try int) error {
if try > 10 {
return errors.New("localstack container has been stopped")
}
containers, err := i.cli.ContainerList(ctx, types.ContainerListOptions{})
func (i *Instance) isRunning(ctx context.Context) error {
_, err := i.cli.ContainerInspect(ctx, i.getContainerId())
if err != nil {
return err
}
for _, c := range containers {
if c.Image == imageName {
return nil
}
i.log.Debug(err)
return errors.New("localstack container has been stopped")
}
time.Sleep(300 * time.Millisecond)
return i.isRunning(ctx, try+1)
return nil
}

func (i *Instance) checkAvailable(ctx context.Context) error {
Expand Down Expand Up @@ -519,9 +511,13 @@ func (i *Instance) setContainerId(v string) {
}

func (i *Instance) resetPortMapping() {
i.savePortMappings(map[Service]string{})
}

func (i *Instance) savePortMappings(newMapping map[Service]string) {
i.portMappingMutex.Lock()
defer i.portMappingMutex.Unlock()
i.portMapping = map[Service]string{}
i.portMapping = newMapping
}

func (i *Instance) getPortMapping(service Service) string {
Expand Down
12 changes: 6 additions & 6 deletions localstack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func TestWithLabels(t *testing.T) {
defer cancel()

require.NoError(t, l.StartWithContext(ctx))
defer func() { require.NoError(t, l.Stop()) }()
t.Cleanup(func() { require.NoError(t, l.Stop()) })

cli, err := client.NewClientWithOpts()
require.NoError(t, err)
Expand Down Expand Up @@ -198,9 +198,9 @@ func TestLocalStack(t *testing.T) {
t.Run(s.name, func(t *testing.T) {
l, err := localstack.NewInstance(s.input...)
require.NoError(t, err)
defer func() {
require.NoError(t, l.Stop())
}()
t.Cleanup(func() {
assert.NoError(t, l.Stop())
})
require.NoError(t, l.Start())
s.expect(t, l)
})
Expand Down Expand Up @@ -304,9 +304,9 @@ func TestLocalStackWithIndividualServices(t *testing.T) {
func TestInstanceStartedTwiceWithoutLeaking(t *testing.T) {
l, err := localstack.NewInstance()
require.NoError(t, err)
defer func() {
t.Cleanup(func() {
require.NoError(t, l.Stop())
}()
})
require.NoError(t, l.Start())
firstInstance := l.Endpoint(localstack.S3)
require.NoError(t, l.Start())
Expand Down

0 comments on commit f9358f5

Please sign in to comment.