Pengambilan Data KFA Pengiriman data medication dan service request
This commit is contained in:
No files matched your search
@@ -18,7 +18,8 @@ import (
|
||||
)
|
||||
|
||||
const trackerFile = "internal/worker/satusehat/medication/last_medication_id.txt"
|
||||
const mappingFile = "internal/worker/satusehat/medication/medication_mapping.txt"
|
||||
const mappingBaseDir = "internal/worker/satusehat/medication/mapperdata"
|
||||
const rateLimitSleep = 60 * time.Second
|
||||
|
||||
type Config struct {
|
||||
DBManager database.Service
|
||||
@@ -98,7 +99,17 @@ func (w *worker) Run(ctx context.Context) {
|
||||
|
||||
internalPayload := MapToInternalAPI(med, w.cfg.OrganizationID, kfaDisplay, formCode, formDisplay)
|
||||
|
||||
fhirID, respBody, status, errMsg, shouldRetry := w.sendToInternalAPI(ctx, internalPayload, med.IdxPesanObat)
|
||||
fhirID, respBody, status, errMsg, shouldRetry, rateLimited := w.sendToInternalAPI(ctx, internalPayload, med.IdxPesanObat)
|
||||
|
||||
if rateLimited {
|
||||
logger.Default().Warn("[MEDICATION WORKER] ⏸️ Rate limit dari Satu Sehat - jeda dan akan retry dokumen yang sama",
|
||||
logger.Int64("idxpesanobat", med.IdxPesanObat),
|
||||
logger.String("response", truncate(string(respBody), 300)),
|
||||
logger.String("sleep", rateLimitSleep.String()),
|
||||
)
|
||||
time.Sleep(rateLimitSleep)
|
||||
continue
|
||||
}
|
||||
|
||||
// Menyimpan payload request dan response ke dalam log
|
||||
logger.Default().Info("[MEDICATION WORKER] Detail Transaksi",
|
||||
@@ -132,7 +143,7 @@ func (w *worker) Run(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]interface{}, idxPesanObat int64) (fhirID string, respBody []byte, status string, errMsg string, shouldRetry bool) {
|
||||
func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]interface{}, idxPesanObat int64) (fhirID string, respBody []byte, status string, errMsg string, shouldRetry bool, rateLimited bool) {
|
||||
reqURL := fmt.Sprintf("%s/satusehat/medication", strings.TrimRight(w.cfg.InternalBaseURL, "/"))
|
||||
|
||||
respBody, statusCode, err := w.apiClient.PostJSON(ctx, reqURL, w.tokenManager.GetAccessToken(), payload)
|
||||
@@ -142,7 +153,7 @@ func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]inter
|
||||
logger.Any("payload_sent", payload),
|
||||
logger.ErrorField(err),
|
||||
)
|
||||
return "", nil, "FAILED", err.Error(), true
|
||||
return "", nil, "FAILED", err.Error(), true, false
|
||||
}
|
||||
|
||||
if statusCode == http.StatusUnauthorized {
|
||||
@@ -151,7 +162,7 @@ func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]inter
|
||||
newToken, refreshErr := w.tokenManager.ForceRefreshAndGetToken(ctx)
|
||||
if refreshErr != nil {
|
||||
logger.Default().Error("[MEDICATION WORKER] Gagal refresh token, akan mencoba lagi pada iterasi berikutnya.", logger.Int64("idxpesanobat", idxPesanObat), logger.ErrorField(refreshErr))
|
||||
return "", respBody, "FAILED", refreshErr.Error(), true
|
||||
return "", respBody, "FAILED", refreshErr.Error(), true, false
|
||||
}
|
||||
|
||||
logger.Default().Info("[MEDICATION WORKER] Token berhasil di-refresh, mencoba ulang request...", logger.Int64("idxpesanobat", idxPesanObat))
|
||||
@@ -161,10 +172,15 @@ func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]inter
|
||||
logger.Int64("idxpesanobat", idxPesanObat),
|
||||
logger.ErrorField(err),
|
||||
)
|
||||
return "", nil, "FAILED", err.Error(), true
|
||||
return "", nil, "FAILED", err.Error(), true, false
|
||||
}
|
||||
}
|
||||
|
||||
if isRateLimitResponse(statusCode, respBody) {
|
||||
errMsg = fmt.Sprintf("HTTP %d - rate limit Satu Sehat", statusCode)
|
||||
return "", respBody, "RATE_LIMITED", errMsg, true, true
|
||||
}
|
||||
|
||||
if statusCode != http.StatusOK && statusCode != http.StatusCreated {
|
||||
errMsg = fmt.Sprintf("HTTP %d", statusCode)
|
||||
logger.Default().Error("[MEDICATION WORKER] ❌ Respons Error dari API Part 3",
|
||||
@@ -173,10 +189,10 @@ func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]inter
|
||||
logger.String("response", truncate(string(respBody), 200)),
|
||||
)
|
||||
|
||||
if statusCode >= 500 || statusCode == http.StatusTooManyRequests {
|
||||
return "", respBody, "FAILED", errMsg, true
|
||||
if statusCode >= 500 {
|
||||
return "", respBody, "FAILED", errMsg, true, false
|
||||
}
|
||||
return "", respBody, "FAILED", errMsg, false
|
||||
return "", respBody, "FAILED", errMsg, false, false
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
@@ -194,7 +210,21 @@ func (w *worker) sendToInternalAPI(ctx context.Context, payload map[string]inter
|
||||
logger.String("fhir_id", fhirID),
|
||||
)
|
||||
|
||||
return fhirID, respBody, "SUCCESS", "", false
|
||||
return fhirID, respBody, "SUCCESS", "", false, false
|
||||
}
|
||||
|
||||
// isRateLimitResponse mendeteksi respons rate-limit dari Satu Sehat
|
||||
// (HTTP 429 atau pesan body yang mengindikasikan limit pengiriman terlampaui).
|
||||
func isRateLimitResponse(statusCode int, respBody []byte) bool {
|
||||
if statusCode == http.StatusTooManyRequests {
|
||||
return true
|
||||
}
|
||||
body := strings.ToLower(string(respBody))
|
||||
return strings.Contains(body, "too many requests") ||
|
||||
strings.Contains(body, "rate limit") ||
|
||||
strings.Contains(body, "limit exceeded") ||
|
||||
strings.Contains(body, "limit pengiriman") ||
|
||||
strings.Contains(body, "quota exceeded")
|
||||
}
|
||||
|
||||
func (w *worker) fetchKFADetails(ctx context.Context, kfaCode string) (kfaDisplay, formCode, formDisplay string) {
|
||||
@@ -301,8 +331,15 @@ func (w *worker) ensureTrackerFileExists() {
|
||||
}
|
||||
|
||||
func (w *worker) saveMapping(idxPesanObat int64, fhirID string) {
|
||||
os.MkdirAll("internal/worker/satusehat/medication", 0755)
|
||||
f, err := os.OpenFile(mappingFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
now := logger.LocalNow()
|
||||
monthDir := filepath.Join(mappingBaseDir, now.Format("2006-01"))
|
||||
if err := os.MkdirAll(monthDir, 0755); err != nil {
|
||||
logger.Default().Error("[MEDICATION WORKER] Gagal membuat direktori mapping bulanan", logger.ErrorField(err))
|
||||
return
|
||||
}
|
||||
|
||||
mappingPath := filepath.Join(monthDir, now.Format("2006-01-02")+".txt")
|
||||
f, err := os.OpenFile(mappingPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
logger.Default().Error("[MEDICATION WORKER] Gagal membuka file mapping", logger.ErrorField(err))
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user