in lambda/rapidcore/server.go [527:593]
func (s *Server) FastInvoke(w http.ResponseWriter, i *interop.Invoke, direct bool) error {
invokeID, err := s.setReplyStream(w, direct)
if err != nil {
return err
}
s.setRapidPhase(phaseInvoking)
i.ID = invokeID
select {
case <-s.sendResponseChan:
// we didn't pass invoke to rapid yet, but rapid already has written some response
// It can happend if runtime/agent crashed even before we passed invoke to it
return ErrInvokeResponseAlreadyWritten
default:
}
go func() {
if s.invoker == nil {
// Reset occurred, do not send invoke request
s.InvokeDoneChan <- DoneWithState{State: s.InternalStateGetter()}
s.setRuntimeState(runtimeInvokeComplete)
return
}
s.invoker.SendRequest(i, s)
invokeSuccess, invokeFailure := s.invoker.Wait()
if invokeFailure != nil {
if invokeFailure.ResetReceived {
return
}
// Rapid constructs a response body itself when invoke fails, with error type.
// These are on the handleInvokeError path, may occur during timeout resets,
// failure reset (proc exit). It is expected to be non-nil on all invoke failures.
if invokeFailure.DefaultErrorResponse == nil {
log.Panicf("default error response was nil for invoke failure, %v", invokeFailure)
}
if cachedInitError := s.getCachedInitErrorResponse(); cachedInitError != nil {
// /init/error was called
s.trySendDefaultErrorResponse(cachedInitError)
} else {
// sent only if /error and /response not called
s.trySendDefaultErrorResponse(invokeFailure.DefaultErrorResponse)
}
doneFail := doneFailFromInvokeFailure(invokeFailure)
s.InvokeDoneChan <- DoneWithState{
Done: &interop.Done{ErrorType: doneFail.ErrorType, Meta: doneFail.Meta},
State: s.InternalStateGetter(),
}
} else {
done := doneFromInvokeSuccess(invokeSuccess)
s.InvokeDoneChan <- DoneWithState{Done: done, State: s.InternalStateGetter()}
}
}()
select {
case i.InvokeResponseMetrics = <-s.sendResponseChan:
s.sandboxContext.SetInvokeResponseMetrics(i.InvokeResponseMetrics)
break
case <-s.reservationContext.Done():
return ErrInvokeReservationDone
}
return nil
}