Pengambilan Data KFA Pengiriman data medication dan service request
This commit is contained in:
No files matched your search
@@ -1 +1 @@
|
||||
3384484
|
||||
3578722
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
@@ -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