diff --git a/contractcourt/channel_arbitrator.go b/contractcourt/channel_arbitrator.go index 099cf06912..a5f75413ca 100644 --- a/contractcourt/channel_arbitrator.go +++ b/contractcourt/channel_arbitrator.go @@ -1575,22 +1575,52 @@ func (c *ChannelArbitrator) resolveContracts(resolvers []ContractResolver) { } } -// launchResolvers launches all the active resolvers. +// launchResolvers launches all the active resolvers concurrently. func (c *ChannelArbitrator) launchResolvers() { - for _, contract := range c.resolvers() { + resolvers := c.resolvers() + + // errChans is a map of channels that will be used to receive errors + // returned from launching the resolvers. + errChans := make(map[ContractResolver]chan error, len(resolvers)) + + // Launch each resolver in goroutines. + for _, r := range resolvers { // If the contract is already resolved, there's no need to // launch it again. - if contract.IsResolved() { + if r.IsResolved() { log.Debugf("ChannelArbitrator(%v): skipping resolver "+ - "%T as it's already resolved", c.id(), contract) + "%T as it's already resolved", c.id(), r) continue } - if err := contract.Launch(); err != nil { + // Create a signal chan. + errChan := make(chan error, 1) + errChans[r] = errChan + + go func() { + err := r.Launch() + errChan <- err + }() + + } + + // Wait for all resolvers to finish launching. + for r, errChan := range errChans { + select { + case err := <-errChan: + if err == nil { + continue + } + log.Errorf("ChannelArbitrator(%v): unable to launch "+ - "contract resolver(%T): %v", c.id(), - contract, err) + "contract resolver(%T): %v", c.id(), r, err) + + case <-c.quit: + log.Debugf("ChannelArbitrator quit signal received, " + + "exit launchResolvers") + + return } } }