1

This is one of my API functions; if I call this function continuously. The api showing loading only. Not getting any response.. then I got 502 error with log

error serving {"error": "context deadline exceeded", "errorVerbose": "context deadline exceeded\ngithub.com/ory/graceful.Graceful.func1\

I am using go-gin

I could not understand what is the issue in my code..

For example, I can call the API 5 times then it showing result. then in the 6th time its loading. its a get function

I could not find the root cause.

My api function is attached:

func (ser *service) GetPlaidUserInstitutionAccounts(ctx context.Context, impartWealthId string) (UserAccount, impart.Error) {

    _, err := dbmodels.Users(dbmodels.UserWhere.ImpartWealthID.EQ(impartWealthId)).One(ctx, ser.db)
    if err != nil {
        impartErr := impart.NewError(impart.ErrBadRequest, "Could not find the user.")
        ser.logger.Error("Could not find the user institution details.", zap.String("User", impartWealthId),
            zap.String("user", impartWealthId))
        return UserAccount{}, impartErr
    }

    userInstitutions, err := dbmodels.UserInstitutions(dbmodels.UserInstitutionWhere.ImpartWealthID.EQ(impartWealthId),
        qm.Load(dbmodels.UserInstitutionRels.ImpartWealth),
        qm.Load(dbmodels.UserInstitutionRels.Institution),
    ).All(ctx, ser.db)

    if len(userInstitutions) == 0 {
        return UserAccount{}, impart.NewError(impart.ErrBadRequest, "No records found.")
    }
    if err != nil {
        impartErr := impart.NewError(impart.ErrBadRequest, "Could not find the user institution details.")
        ser.logger.Error("Could not find the user institution details.", zap.String("User", impartWealthId),
            zap.String("user", impartWealthId))
        return UserAccount{}, impartErr
    }

    configuration := plaid.NewConfiguration()
    cfg, _ := config.GetImpart()
    if cfg != nil {
        configuration.AddDefaultHeader("PLAID-CLIENT-ID", cfg.PlaidClientId)
        configuration.AddDefaultHeader("PLAID-SECRET", cfg.PlaidSecret)

        if cfg.Env == config.Production {
            configuration.UseEnvironment(plaid.Production)
        } else if cfg.Env == config.Preproduction {
            configuration.UseEnvironment(plaid.Development)
        } else {
            configuration.UseEnvironment(plaid.Sandbox)
        }

    }
    client := plaid.NewAPIClient(configuration)

    userData := UserAccount{}
    userData.ImpartWealthID = impartWealthId
    userData.UpdatedAt = time.Now().UTC().Unix()
    userinstitution := make(UserInstitutions, len(userInstitutions))
    finalQuery := ""
    for i, user := range userInstitutions {
        institution := InstitutionToModel(user)
        accountsGetRequest := plaid.NewAccountsGetRequest(user.AccessToken)
        accountsGetResp, response, err := client.PlaidApi.AccountsGet(ctx).AccountsGetRequest(
            *accountsGetRequest,
        ).Execute()

        if response.StatusCode == 400 {
            // defer response.Body.Close()
            bodyBytes, _ := ioutil.ReadAll(response.Body)
            type errorResponse struct {
                ErrorCode string `json:"error_code" `
            }
            newRes := errorResponse{}
            err = json.Unmarshal(bodyBytes, &newRes)
            if err != nil {
                fmt.Println(err)
            }
            if newRes.ErrorCode == "ITEM_LOGIN_REQUIRED" {
                institution.IsAuthenticationError = true
            }
        }
        if err != nil {
            ser.logger.Error("Could not find the user plaid account details.", zap.String("User", impartWealthId),
                zap.String("token", user.AccessToken))
            continue
        }
        accounts := accountsGetResp.GetAccounts()
        userAccounts := make(Accounts, len(accounts))
        query1 := ""
        query := ""
        logwrite := false
        for i, act := range accounts {
            userAccounts[i], query1 = AccountToModel(act, user.UserInstitutionID)
            query = fmt.Sprintf("%s %s", query, query1)
            logwrite = true
        }
        institution.Accounts = userAccounts
        userinstitution[i] = institution
        userData.Institutions = userinstitution

        if logwrite {
            finalQuery = fmt.Sprintf("%s %s", finalQuery, query)
        }
    }
    if finalQuery != "" {
        go func() {
            lastQuery := "INSERT INTO `user_plaid_accounts_log` (`user_institution_id`,`account_id`,`mask`,`name`,`official_name`,`subtype`,`type`,`iso_currency_code`,`unofficial_currency_code`,`available`,`current`,`credit_limit`,`created_at`) VALUES "
            lastQuery = fmt.Sprintf("%s %s", lastQuery, finalQuery)
            lastQuery = strings.Trim(lastQuery, ",")
            lastQuery1 = fmt.Sprintf("%s ;", lastQuery)
            ser.logger.Info("Query", zap.Any("Query", lastQuery1))
            _, err = queries.Raw(lastQuery1).QueryContext(ctx, ser.db)
            if err != nil {
                ser.logger.Error("error attempting to  log in user_plaid_accounts_log ", zap.Any("user_plaid_accounts_log", lastQuery1), zap.Error(err))
            }
        }()
    }
    return userData, nil
}

Here I am getting error in main.go

if err := graceful.Graceful(server.ListenAndServe, server.Shutdown); err != nil {
        logger.Fatal("error serving", zap.Error(err))
    }
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Mia Mia
  • 143
  • 12
  • 1
    Look, your top-level function received a `context.Context` (which supposedly is a deadline-class context, whose deadline gets expired) in the variable called `ctx`. This variable is then passed to a number of other calls, _each_ of which may return an error, and hence each such error may be due to that context having been cancelled in the midst of that function carrying out its intended task. So a way to debug that is to wrap each error returned by those function with a bit of context so that you know which one had actually terminated. – kostix Dec 06 '21 at 19:41
  • Like with `foo, err := function(ctx, ...); if err != ni { return fmt.Errorf("failed to frobnicate fizzles: %v", err) }` – kostix Dec 06 '21 at 19:42
  • Once you have located which function fails to complete its task before the deadline ends, it worth closed investigation. I'd add debug printouts with `time.Now()` before and after the function gets executed, or so. Also keep in mind that the deadline is for the whole operation, so if, say, the deadline was set for 10 seconds before the call to the top-level functions, and it executes 4 functions with each spending 3 seconds, there may be no one single "outlier" function which is slow: all of them just may add delay gradually. – kostix Dec 06 '21 at 19:45

0 Answers0