func()

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
}