5050 _ rest.GracefulDeleter = (* TemplateStorage )(nil )
5151 _ rest.Scoper = (* TemplateStorage )(nil )
5252 _ rest.SingularNameProvider = (* TemplateStorage )(nil )
53+
54+ errTemplateVersionBuildWaitTimeoutExceeded = errors .New ("template version build wait timeout exceeded" )
5355)
5456
5557// TemplateStorage provides codersdk-backed CoderTemplate objects.
@@ -687,7 +689,14 @@ func mapTemplateVersionBuildWaitError(waitErr error, templateName string) error
687689
688690 var timeoutErr * templateVersionBuildWaitTimeoutError
689691 if errors .As (waitErr , & timeoutErr ) {
690- return apierrors .NewBadRequest (timeoutErr .Error ())
692+ switch {
693+ case errors .Is (timeoutErr .cause , errTemplateVersionBuildWaitTimeoutExceeded ):
694+ return apierrors .NewBadRequest (timeoutErr .Error ())
695+ case errors .Is (timeoutErr .cause , context .DeadlineExceeded ), errors .Is (timeoutErr .cause , context .Canceled ):
696+ return apierrors .NewTimeoutError (timeoutErr .Error (), 0 )
697+ default :
698+ return apierrors .NewInternalError (timeoutErr )
699+ }
691700 }
692701
693702 return coder .MapCoderError (waitErr , aggregationv1alpha1 .Resource ("codertemplates" ), templateName )
@@ -709,7 +718,15 @@ func waitForTemplateVersionBuild(ctx context.Context, sdk *codersdk.Client, vers
709718 return waitConfigErr
710719 }
711720
712- waitCtx , cancel := context .WithTimeout (ctx , waitConfig .waitTimeout )
721+ effectiveWaitTimeout := waitConfig .waitTimeout
722+ if requestDeadline , hasRequestDeadline := ctx .Deadline (); hasRequestDeadline {
723+ remaining := time .Until (requestDeadline )
724+ if remaining > 0 && remaining < effectiveWaitTimeout {
725+ effectiveWaitTimeout = remaining
726+ }
727+ }
728+
729+ waitCtx , cancel := context .WithTimeout (ctx , effectiveWaitTimeout )
713730 defer cancel ()
714731
715732 pollInterval := waitConfig .initialPoll
@@ -721,12 +738,17 @@ func waitForTemplateVersionBuild(ctx context.Context, sdk *codersdk.Client, vers
721738 version , err := sdk .TemplateVersion (waitCtx , versionID )
722739 if err != nil {
723740 if waitCtx .Err () != nil {
741+ timeoutCause , timeoutCauseErr := templateVersionBuildWaitTimeoutCause (ctx , waitCtx )
742+ if timeoutCauseErr != nil {
743+ return timeoutCauseErr
744+ }
745+
724746 return & templateVersionBuildWaitTimeoutError {
725747 versionID : versionID ,
726- waitTimeout : waitConfig . waitTimeout ,
748+ waitTimeout : effectiveWaitTimeout ,
727749 lastStatus : lastStatus ,
728750 lastError : lastError ,
729- cause : waitCtx . Err () ,
751+ cause : timeoutCause ,
730752 }
731753 }
732754 return fmt .Errorf ("fetch template version %q: %w" , versionID .String (), err )
@@ -771,21 +793,47 @@ func waitForTemplateVersionBuild(ctx context.Context, sdk *codersdk.Client, vers
771793
772794 select {
773795 case <- waitCtx .Done ():
774- if waitCtx .Err () == nil {
775- return fmt .Errorf ("assertion failed: wait context finished without an error" )
796+ timeoutCause , timeoutCauseErr := templateVersionBuildWaitTimeoutCause (ctx , waitCtx )
797+ if timeoutCauseErr != nil {
798+ return timeoutCauseErr
776799 }
800+
777801 return & templateVersionBuildWaitTimeoutError {
778802 versionID : versionID ,
779- waitTimeout : waitConfig . waitTimeout ,
803+ waitTimeout : effectiveWaitTimeout ,
780804 lastStatus : lastStatus ,
781805 lastError : lastError ,
782- cause : waitCtx . Err () ,
806+ cause : timeoutCause ,
783807 }
784808 case <- time .After (pollInterval ):
785809 }
786810 }
787811}
788812
813+ func templateVersionBuildWaitTimeoutCause (requestCtx , waitCtx context.Context ) (error , error ) {
814+ if requestCtx == nil {
815+ return nil , fmt .Errorf ("assertion failed: request context must not be nil" )
816+ }
817+ if waitCtx == nil {
818+ return nil , fmt .Errorf ("assertion failed: wait context must not be nil" )
819+ }
820+
821+ waitErr := waitCtx .Err ()
822+ if waitErr == nil {
823+ return nil , fmt .Errorf ("assertion failed: wait context finished without an error" )
824+ }
825+
826+ if requestErr := requestCtx .Err (); requestErr != nil {
827+ return requestErr , nil
828+ }
829+
830+ if errors .Is (waitErr , context .DeadlineExceeded ) {
831+ return errTemplateVersionBuildWaitTimeoutExceeded , nil
832+ }
833+
834+ return waitErr , nil
835+ }
836+
789837func loadTemplateVersionBuildWaitConfigFromEnv () (templateVersionBuildWaitConfig , error ) {
790838 waitTimeout , waitTimeoutErr := parseDurationEnvOrDefault (templateVersionBuildWaitTimeoutEnv , defaultTemplateVersionBuildWaitTimeout )
791839 if waitTimeoutErr != nil {
0 commit comments