in lambda/rapidcore/server.go [577:651]
func (s *Server) Invoke(responseWriter http.ResponseWriter, invoke *interop.Invoke) error {
resetCtx, resetCancel := context.WithCancel(context.Background())
defer resetCancel()
timeoutChan := make(chan error)
go func() {
select {
case <-time.After(s.GetInvokeTimeout()):
timeoutChan <- ErrInvokeTimeout
s.Reset(autoresetReasonTimeout, resetDefaultTimeoutMs)
case <-resetCtx.Done():
log.Debugf("execute finished, autoreset cancelled")
}
}()
reserveResp, err := s.Reserve(invoke.ID, "", "")
if err != nil {
switch err {
case ErrInitError:
// Simulate 'Suppressed Init' scenario
s.Reset(autoresetReasonReserveFail, resetDefaultTimeoutMs)
reserveResp, err = s.Reserve("", "", "")
if err == ErrInitAlreadyDone {
break
}
return err
case ErrInitDoneFailed, ErrTerminated:
s.Reset(autoresetReasonReserveFail, resetDefaultTimeoutMs)
return err
case ErrInitAlreadyDone:
// This is a valid response (e.g. for 2nd and 3rd invokes)
// TODO: switch on ReserveResponse status instead of err,
// since these are valid values
if s.InternalStateGetter == nil {
responseWriter.Write([]byte("error: internal state callback not set"))
return ErrInternalServerError
}
default:
return err
}
}
invoke.DeadlineNs = fmt.Sprintf("%d", metering.Monotime()+reserveResp.Token.FunctionTimeout.Nanoseconds())
invokeChan := make(chan error)
go func() {
if err := s.FastInvoke(responseWriter, invoke, false); err != nil {
invokeChan <- err
}
}()
releaseChan := make(chan error)
go func() {
_, err := s.AwaitRelease()
releaseChan <- err
}()
// TODO: verify the order of channel receives. When timeouts happen, Reset()
// is called first, which also does Release() => this may signal a type
// Err<*>ReservationDone error to the non-timeout channels. This is currently
// handled by the http handler, which returns GatewayTimeout for reservation errors
// too. However, Timeouts should ideally be only represented by ErrInvokeTimeout.
select {
case err = <-invokeChan:
case err = <-timeoutChan:
case err = <-releaseChan:
if err != nil {
s.Reset(autoresetReasonReleaseFail, resetDefaultTimeoutMs)
}
}
return err
}