Skip to content

Commit dd4fec8

Browse files
prakash100198komalreddy3
authored andcommitted
fix: handle 5xx in fetch resource tree api and cd-trigger (#5050)
* handle context cancelled and deadline exceeded in fetch resource tree api * handle context cancelled and deadline exceeded error for resource tree fetch api for acd deployment * handle context cancelled and deadline exceeded error sync argo app with normal refresh * revert TIMEOUT_IN_SECONDS * revert bean TimeoutSlow param * fix
1 parent 972471b commit dd4fec8

File tree

5 files changed

+86
-9
lines changed

5 files changed

+86
-9
lines changed

api/restHandler/app/appList/AppListingRestHandler.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ package appList
2020
import (
2121
"context"
2222
"encoding/json"
23+
"errors"
2324
"fmt"
2425
"github.com/devtron-labs/devtron/api/helm-app/gRPC"
2526
client "github.com/devtron-labs/devtron/api/helm-app/service"
@@ -645,26 +646,34 @@ func (handler AppListingRestHandlerImpl) FetchResourceTree(w http.ResponseWriter
645646

646647
func (handler AppListingRestHandlerImpl) handleResourceTreeErrAndDeletePipelineIfNeeded(w http.ResponseWriter, err error,
647648
appId int, envId int, acdToken string, cdPipeline *pipelineConfig.Pipeline) {
649+
var apiError *util.ApiError
650+
ok := errors.As(err, &apiError)
648651
if cdPipeline.DeploymentAppType == util.PIPELINE_DEPLOYMENT_TYPE_ACD {
649-
apiError, ok := err.(*util.ApiError)
650652
if ok && apiError != nil {
651653
if apiError.Code == constants.AppDetailResourceTreeNotFound && cdPipeline.DeploymentAppDeleteRequest == true && cdPipeline.DeploymentAppCreated == true {
652654
acdAppFound, appDeleteErr := handler.pipeline.MarkGitOpsDevtronAppsDeletedWhereArgoAppIsDeleted(appId, envId, acdToken, cdPipeline)
653655
if appDeleteErr != nil {
654-
common.WriteJsonResp(w, fmt.Errorf("error in deleting devtron pipeline for deleted argocd app"), nil, http.StatusInternalServerError)
656+
apiError.UserMessage = constants.ErrorDeletingPipelineForDeletedArgoAppMsg
657+
common.WriteJsonResp(w, apiError, nil, http.StatusInternalServerError)
655658
return
656659
} else if appDeleteErr == nil && !acdAppFound {
657-
common.WriteJsonResp(w, fmt.Errorf("argocd app deleted"), nil, http.StatusNotFound)
660+
apiError.UserMessage = constants.ArgoAppDeletedErrMsg
661+
common.WriteJsonResp(w, apiError, nil, http.StatusNotFound)
658662
return
659663
}
660664
}
661665
}
662666
}
663667
// not returned yet therefore no specific error to be handled, send error in internal message
664-
common.WriteJsonResp(w, &util.ApiError{
665-
InternalMessage: err.Error(),
666-
UserMessage: "unable to fetch resource tree",
667-
}, nil, http.StatusInternalServerError)
668+
if ok && apiError != nil {
669+
apiError.UserMessage = constants.UnableToFetchResourceTreeErrMsg
670+
} else {
671+
apiError = &util.ApiError{
672+
InternalMessage: err.Error(),
673+
UserMessage: constants.UnableToFetchResourceTreeErrMsg,
674+
}
675+
}
676+
common.WriteJsonResp(w, apiError, nil, http.StatusInternalServerError)
668677
}
669678

670679
func (handler AppListingRestHandlerImpl) FetchAppStageStatus(w http.ResponseWriter, r *http.Request) {
@@ -1007,9 +1016,13 @@ func (handler AppListingRestHandlerImpl) fetchResourceTree(w http.ResponseWriter
10071016
handler.logger.Debugw("FetchAppDetailsV2, time elapsed in fetching application for environment ", "elapsed", elapsed, "appId", appId, "envId", envId)
10081017
if err != nil {
10091018
handler.logger.Errorw("service err, FetchAppDetailsV2, resource tree", "err", err, "app", appId, "env", envId)
1019+
internalMsg := fmt.Sprintf("%s, err:- %s", constants.UnableToFetchResourceTreeForAcdErrMsg, err.Error())
1020+
clientCode, _ := util.GetClientDetailedError(err)
1021+
httpStatusCode := clientCode.GetHttpStatusCodeForGivenGrpcCode()
10101022
err = &util.ApiError{
1023+
HttpStatusCode: httpStatusCode,
10111024
Code: constants.AppDetailResourceTreeNotFound,
1012-
InternalMessage: "app detail fetched, failed to get resource tree from acd",
1025+
InternalMessage: internalMsg,
10131026
UserMessage: "Error fetching detail, if you have recently created this deployment pipeline please try after sometime.",
10141027
}
10151028
return resourceTree, err
@@ -1110,6 +1123,10 @@ func (handler AppListingRestHandlerImpl) fetchResourceTree(w http.ResponseWriter
11101123
resp, err := handler.k8sCommonService.GetManifestsByBatch(r.Context(), validRequest)
11111124
if err != nil {
11121125
handler.logger.Errorw("error in getting manifest by batch", "err", err, "clusterId", clusterIdString)
1126+
httpStatus, ok := util.IsErrorContextCancelledOrDeadlineExceeded(err)
1127+
if ok {
1128+
return nil, &util.ApiError{HttpStatusCode: httpStatus, Code: strconv.Itoa(httpStatus), InternalMessage: err.Error()}
1129+
}
11131130
return nil, err
11141131
}
11151132
newResourceTree := handler.k8sCommonService.PortNumberExtraction(resp, resourceTree)

client/argocdServer/ArgoClientWrapperService.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ import (
1212
"github.com/devtron-labs/devtron/client/argocdServer/application"
1313
"github.com/devtron-labs/devtron/client/argocdServer/bean"
1414
"github.com/devtron-labs/devtron/client/argocdServer/repository"
15+
"github.com/devtron-labs/devtron/internal/constants"
1516
"github.com/devtron-labs/devtron/internal/util"
1617
"github.com/devtron-labs/devtron/pkg/deployment/gitOps/config"
1718
"github.com/devtron-labs/devtron/pkg/deployment/gitOps/git"
1819
"github.com/devtron-labs/devtron/util/retryFunc"
1920
"go.uber.org/zap"
2021
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
22+
"strconv"
2123
"strings"
2224
"time"
2325
)
@@ -101,6 +103,10 @@ func (impl *ArgoClientWrapperServiceImpl) GetArgoAppWithNormalRefresh(context co
101103
impl.logger.Debugw("trying to normal refresh application through get ", "argoAppName", argoAppName)
102104
_, err := impl.acdClient.Get(context, &application2.ApplicationQuery{Name: &argoAppName, Refresh: &refreshType})
103105
if err != nil {
106+
internalMsg := fmt.Sprintf("%s, err:- %s", constants.CannotGetAppWithRefreshErrMsg, err.Error())
107+
clientCode, _ := util.GetClientDetailedError(err)
108+
httpStatusCode := clientCode.GetHttpStatusCodeForGivenGrpcCode()
109+
err = &util.ApiError{HttpStatusCode: httpStatusCode, Code: strconv.Itoa(httpStatusCode), InternalMessage: internalMsg, UserMessage: err.Error()}
104110
impl.logger.Errorw("cannot get application with refresh", "app", argoAppName)
105111
return err
106112
}

internal/constants/InternalErrorCode.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,17 @@ const (
9494
VulnerabilityFound string = "10002"
9595
)
9696

97+
const (
98+
HttpClientSideTimeout = 499
99+
)
100+
97101
var AppAlreadyExists = &ErrorCode{"4001", "application %s already exists"}
98102
var AppDoesNotExist = &ErrorCode{"4004", "application %s does not exist"}
103+
104+
const (
105+
ErrorDeletingPipelineForDeletedArgoAppMsg = "error in deleting devtron pipeline for deleted argocd app"
106+
ArgoAppDeletedErrMsg = "argocd app deleted"
107+
UnableToFetchResourceTreeErrMsg = "unable to fetch resource tree"
108+
UnableToFetchResourceTreeForAcdErrMsg = "app detail fetched, failed to get resource tree from acd"
109+
CannotGetAppWithRefreshErrMsg = "cannot get application with refresh"
110+
)

internal/errors/bean.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package errors
22

3-
import "google.golang.org/grpc/codes"
3+
import (
4+
"github.com/devtron-labs/devtron/internal/constants"
5+
"google.golang.org/grpc/codes"
6+
"net/http"
7+
)
48

59
type ClientStatusCode struct {
610
Code codes.Code
@@ -17,3 +21,28 @@ func (r *ClientStatusCode) IsNotFoundCode() bool {
1721
func (r *ClientStatusCode) IsFailedPreconditionCode() bool {
1822
return r.Code == codes.FailedPrecondition
1923
}
24+
25+
func (r *ClientStatusCode) IsDeadlineExceededCode() bool {
26+
return r.Code == codes.DeadlineExceeded
27+
}
28+
29+
func (r *ClientStatusCode) IsCanceledCode() bool {
30+
return r.Code == codes.Canceled
31+
}
32+
33+
func (r *ClientStatusCode) GetHttpStatusCodeForGivenGrpcCode() int {
34+
switch r.Code {
35+
case codes.InvalidArgument:
36+
return http.StatusConflict
37+
case codes.NotFound:
38+
return http.StatusNotFound
39+
case codes.FailedPrecondition:
40+
return http.StatusPreconditionFailed
41+
case codes.DeadlineExceeded:
42+
return http.StatusRequestTimeout
43+
case codes.Canceled:
44+
return constants.HttpClientSideTimeout
45+
default:
46+
return http.StatusInternalServerError
47+
}
48+
}

internal/util/ErrorUtil.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
package util
1919

2020
import (
21+
"context"
22+
errors2 "errors"
2123
"fmt"
24+
"github.com/devtron-labs/devtron/internal/constants"
2225
"github.com/devtron-labs/devtron/internal/errors"
2326
"github.com/go-pg/pg"
2427
"google.golang.org/grpc/codes"
2528
"google.golang.org/grpc/status"
29+
"net/http"
2630
)
2731

2832
type ApiError struct {
@@ -66,3 +70,12 @@ func GetClientDetailedError(err error) (*errors.ClientStatusCode, string) {
6670
}
6771
return grpcCode, err.Error()
6872
}
73+
74+
func IsErrorContextCancelledOrDeadlineExceeded(err error) (int, bool) {
75+
if errors2.Is(err, context.Canceled) {
76+
return constants.HttpClientSideTimeout, true
77+
} else if errors2.Is(err, context.DeadlineExceeded) {
78+
return http.StatusRequestTimeout, true
79+
}
80+
return 0, false
81+
}

0 commit comments

Comments
 (0)