code: func (e *engineImpl) allocateInvocations(c context.Context, job *Job, req []task.Request) ([]*Invocation, error) {
  	wg := sync.WaitGroup{}
  	wg.Add(len(req))
  
  	invs := make([]*Invocation, len(req))
  	merr := errors.NewLazyMultiError(len(req))
  	for i := range req {
  		go func(i int) {
  			defer wg.Done()
  			inv, err := e.allocateInvocation(c, job, req[i])
  			invs[i] = inv
  			merr.Assign(i, err)
  			if err != nil {
  				logging.WithError(err).Errorf(c, "Failed to create invocation with %d triggers", len(req[i].IncomingTriggers))
  			}
  		}(i)
  	}
  
  	wg.Wait()
  
  	// Bail if any of them failed. Try best effort cleanup.
  	if err := merr.Get(); err != nil {
  		cleanupUnreferencedInvocations(c, invs)
  		return nil, transient.Tag.Apply(err)
  	}
  
  	return invs, nil
  }
docs: // allocateInvocations is a batch version of allocateInvocation.
  //
  // It launches N independent transactions in parallel to create N invocations.