Контент, написанный автору ответа, показывает ошибочное поведение
Файл: main.go
import (
"github.com/gorilla/mux"
)
func setupRouting(pBus *bus.Bus) *mux.Router {
log.Debug("Setting up routing")
r := mux.NewRouter()
pInvoiceHandler := handlers.NewInvoiceHandler(pBus)
postRouter.HandleFunc("/invoice", pInvoiceHandler.HandleInvoiceGenerationRequest)
return r
}
main() {
pRouter := setupRouting(pBus)
s := &http.Server{
Addr: address,
Handler: pRouter,
IdleTimeout: time.Duration(idlTimeout) * time.Second,
ReadTimeout: time.Duration(rdTimeout) * time.Second,
WriteTimeout: time.Duration(wrtTimeout) * time.Second,
}
}
Файл: InvoiceGenerationHandler.go
func (ih *InvoiceHandler) HandleInvoiceGenerationRequest(rw http.ResponseWriter, pReq *http.Request) {
log.Info("Handling invoice generation request")
query := pReq.URL.Query()
resourceGrp := query.Get("rGrp")
if resourceGrp == "" {
http.Error(rw, "Invalid URL, rGrp parameter should be present in the URL ", http.StatusBadRequest)
return
}
pSliceCostDetailsCtx, err := ih.pApiLoadTesting.CalculateCost(resourceGrp)
if err != nil {
log.Error("Could not calculate cost :", err.Error())
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
pResponseJson, err := json.Marshal(pSliceCostDetailsCtx)
if err != nil {
log.Error("Could not convert price context slice to json: ", err.Error())
http.Error(rw, "Could not generate cost response", http.StatusInternalServerError)
log.Error(pResponseJson)
return
}
rw.Write(pResponseJson)
}
Файл: apiloadtestpricing.go
type ApiLoadTestPricing struct {
mpHttpClient *http.Client
}
func NewApiLoadTesting() *ApiLoadTestPricing {
var pHttpClient = &http.Client{
Timeout: time.Second * 120,
}
return &ApiLoadTestPricing{pHttpClient}
}
func getBearerToken(pHttpClient *http.Client, microsoftTokenEndpoint string) (string, error) {
v := url.Values{}
v.Set("grant_type", "client_credentials")
v.Set("client_id", "******************************")
v.Set("client_secret", "**************************")
v.Set("resource", "https://management.core.windows.net")
params := strings.NewReader(v.Encode())
req, err := http.NewRequest(http.MethodPost, microsoftTokenEndpoint, params)
if err != nil {
log.Error("Could not create a new request")
log.Error("Encountered error: ", err.Error())
return "", err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Host", "login.microsoftonline.com")
resp, err := pHttpClient.Do(req)
if err != nil {
log.Error("Could not get token from microsoft token endpoint ", microsoftTokenEndpoint)
log.Error("Encountered error: ", err.Error())
return "", err
}
/* More Code here not shown */
}
func getCostFromAzureCostManagement(pHttpClient *http.Client, bearerToken string, resourcegroup string) (*[]models.CostDetailsContext, error) {
log.Info("Getting Cost from Azure")
url := "https://management.azure.com/subscriptions/6a877c8f-4ca3-4135-9a0c-8e92db2384b4/resourceGroups/" + resourcegroup + "/providers/Microsoft.CostManagement/query?api-version=2021-10-01"
postBody := `{
"type": "Usage",
"timeframe": "MonthToDate",
"dataset": {
"granularity": "Daily",
"aggregation": {
"totalCost": {
"name": "PreTaxCost",
"function": "Sum"
}
},
"grouping": [
{
"type": "Dimension",
"name": "resourceGroup"
}
]
}
}`
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(postBody))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", bearerToken)
resp, err := pHttpClient.Do(req)
/* More Code here not shown */
}
func (pPrice *ApiLoadTestPricing) CalculateCost(rGrp string) (*[]models.CostDetailsContext, error) {
log.Info("Calculating cost from azure for resource group: ", rGrp)
token, err := getBearerToken(pPrice.mpHttpClient, "https://login.microsoftonline.com/7a9376d4-7c43-480f-82ba-a090647f651d/oauth2/token")
if err != nil {
log.Error("Cost calculation has failed because proper bearer token was not present")
return nil, err
}
pSliceCostDetailsContext, err := getCostFromAzureCostManagement(pPrice.mpHttpClient, "Bearer "+token, rGrp)
return pSliceCostDetailsContext, err
}
Постановка задачи:
Я написал небольшой API на golang, который делает две вещи: 1. Получает токен Bearer из активного каталога Azure. 2. Вызывает API управления затратами Microsoft, чтобы получить стоимость группы ресурсов.
Проблема. Случай 1. При вызове getBearerToken и getCostFromAzureCostManagement. Ответ, написанный автору ответа в InvoiceGenerationHandler.go, иногда доходит до клиента, а иногда нет.
Случай 2: когда вызывается только getBearerToken и возвращается строка токена, она достигает клиента при каждой записи.
Примечание:
- И getBearerToken, и getCostFromAzureCostManagement используют один и тот же http-клиент для запроса.
- gorilla mux используется для маршрутизации
Что я сделал ?
- Пробовал закомментировать код CalculateCost - работает писатель ответов.
- Пробовал закомментировать getCostFromAzureCostManagement - работает responsewriter
- Пробовал с обоими без комментариев - reponsewriter не работает
- Прочитайте о возможной проблеме с общим httpclient и попробуйте следующий код https://github.com/hashicorp/go-cleanhttp - Responsewriter не работает.
Я застрял с этим, и у меня закончились идеи, может кто-нибудь помочь мне отладить это?
1 ответ
Попробуйте увеличить таймауты.
IdleTimeout: 60 * time.Second,
ReadTimeout: 60* time.Second,
WriteTimeout: 60* time.Second,