279 lines
8.6 KiB
Go
279 lines
8.6 KiB
Go
package worker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"service/internal/infrastructure/config"
|
|
"service/internal/infrastructure/database"
|
|
"service/internal/interfaces/satusehat"
|
|
"service/internal/worker/satusehat/allergyintolerance"
|
|
"service/internal/worker/satusehat/careplan"
|
|
"service/internal/worker/satusehat/clinicalimpression"
|
|
"service/internal/worker/satusehat/composition"
|
|
"service/internal/worker/satusehat/condition"
|
|
"service/internal/worker/satusehat/diagnosticreport"
|
|
"service/internal/worker/satusehat/encounter"
|
|
"service/internal/worker/satusehat/episodeofcare"
|
|
"service/internal/worker/satusehat/imagingstudy"
|
|
"service/internal/worker/satusehat/immunization"
|
|
"service/internal/worker/satusehat/medication"
|
|
"service/internal/worker/satusehat/medicationdispense"
|
|
"service/internal/worker/satusehat/medicationrequest"
|
|
"service/internal/worker/satusehat/medicationstatement"
|
|
"service/internal/worker/satusehat/observation"
|
|
"service/internal/worker/satusehat/procedure"
|
|
"service/internal/worker/satusehat/questionnaireresponse"
|
|
"service/internal/worker/satusehat/servicerequest"
|
|
"service/internal/worker/satusehat/specimen"
|
|
"service/pkg/logger"
|
|
)
|
|
|
|
// Manager mengelola siklus hidup semua background workers
|
|
type Manager struct {
|
|
cfg *config.Config
|
|
db database.Service
|
|
satusehatClient satusehat.SatuSehatClient
|
|
}
|
|
|
|
// NewManager membuat instance Manager baru
|
|
func NewManager(cfg *config.Config, db database.Service, satusehatClient satusehat.SatuSehatClient) *Manager {
|
|
return &Manager{
|
|
cfg: cfg,
|
|
db: db,
|
|
satusehatClient: satusehatClient,
|
|
}
|
|
}
|
|
|
|
// Start menjalankan semua worker terdaftar dalam goroutine terpisah
|
|
func (m *Manager) Start(ctx context.Context) {
|
|
logger.Default().Info("Starting background workers...")
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Tentukan Organization ID (Bisa dari Environment Variable atau Config Struct)
|
|
orgID := os.Getenv("SATUSEHAT_ORGANIZATION_ID")
|
|
if orgID == "" {
|
|
logger.Default().Warn("SATUSEHAT_ORGANIZATION_ID is not set in environment variables")
|
|
}
|
|
|
|
internalPort := 8080
|
|
if m.cfg != nil && m.cfg.Server.REST.Port != 0 {
|
|
internalPort = m.cfg.Server.REST.Port
|
|
}
|
|
internalBaseURL := fmt.Sprintf("http://localhost:%d/api/v1", internalPort)
|
|
internalToken := os.Getenv("INTERNAL_API_TOKEN")
|
|
|
|
// Jobs mendefinisikan urutan dan jeda waktu (delay) boot-up setiap worker.
|
|
// Konfigurasi waktu ini mencegah perebutan resource di awal (thundering herd)
|
|
// dan memastikan resource inti (seperti Encounter) mendapat "head start"
|
|
// sebelum worker anak mencoba merujuk ke data tersebut.
|
|
jobs := []struct {
|
|
name string
|
|
delay time.Duration
|
|
run func(context.Context)
|
|
}{
|
|
{
|
|
name: "Medication (Master)",
|
|
delay: 0, // Master data berjalan seketika
|
|
run: func(c context.Context) {
|
|
medication.NewWorker(medication.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Encounter",
|
|
delay: 5 * time.Second, // Memberikan jeda 5 detik agar Encounter mendapat porsi jalan lebih dulu
|
|
run: func(c context.Context) {
|
|
encounter.NewWorker(encounter.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Condition",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
condition.NewWorker(condition.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Observation",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
observation.NewWorker(observation.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Procedure",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
procedure.NewWorker(procedure.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "AllergyIntolerance",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
allergyintolerance.NewWorker(allergyintolerance.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "ClinicalImpression",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
clinicalimpression.NewWorker(clinicalimpression.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Immunization",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
immunization.NewWorker(immunization.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "ServiceRequest",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
servicerequest.NewWorker(servicerequest.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Specimen",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
specimen.NewWorker(specimen.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "DiagnosticReport",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
diagnosticreport.NewWorker(diagnosticreport.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "ImagingStudy",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
imagingstudy.NewWorker(imagingstudy.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "Composition",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
composition.NewWorker(composition.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "CarePlan",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
careplan.NewWorker(careplan.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "EpisodeOfCare",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
episodeofcare.NewWorker(episodeofcare.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "MedicationRequest",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
medicationrequest.NewWorker(medicationrequest.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "MedicationDispense",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
medicationdispense.NewWorker(medicationdispense.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "MedicationStatement",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
medicationstatement.NewWorker(medicationstatement.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
{
|
|
name: "QuestionnaireResponse",
|
|
delay: 2 * time.Second,
|
|
run: func(c context.Context) {
|
|
questionnaireresponse.NewWorker(questionnaireresponse.Config{
|
|
DBManager: m.db, InternalBaseURL: internalBaseURL, InternalToken: internalToken, OrganizationID: orgID,
|
|
}).Run(c)
|
|
},
|
|
},
|
|
}
|
|
|
|
// Eksekusi semua background worker secara tertib
|
|
go func() {
|
|
for _, job := range jobs {
|
|
// Jeda startup, dapat di-interrupt oleh Context Cancel (Shutdown System)
|
|
if job.delay > 0 {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-time.After(job.delay):
|
|
}
|
|
}
|
|
|
|
wg.Add(1)
|
|
j := job // copy pointer untuk goroutine loop
|
|
go func() {
|
|
defer wg.Done()
|
|
logger.Default().Info(fmt.Sprintf("[%s WORKER] Started", j.name))
|
|
j.run(ctx)
|
|
logger.Default().Info(fmt.Sprintf("[%s WORKER] Stopped", j.name))
|
|
}()
|
|
}
|
|
|
|
// Waiter untuk Graceful Shutdown keseluruhan
|
|
wg.Wait()
|
|
logger.Default().Info("All background workers stopped gracefully")
|
|
}()
|
|
}
|