perf: wire job_audit terminal persistence hook
CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Failing after 35s
CI / go (push) Failing after 30s
CI / bird2 (push) Has been skipped
CI / release (push) Has been skipped
CI / changes (push) Successful in 8s
CI / commitlint (push) Has been skipped
CI / openapi (push) Has been skipped
CI / web (push) Failing after 35s
CI / go (push) Failing after 30s
CI / bird2 (push) Has been skipped
CI / release (push) Has been skipped
- TerminalHook в Registry для записи статуса job в PostgreSQL job_audit - Подключение через BootstrapWorkers при наличии pool Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -53,6 +53,21 @@ func BootstrapWorkers(ctx context.Context, opts Options) (store.Backend, *jobs.R
|
|||||||
wk := &jobs.Worker{Store: backend, HTTPClient: cdnHTTP}
|
wk := &jobs.Worker{Store: backend, HTTPClient: cdnHTTP}
|
||||||
reg := jobs.NewRegistry(wk.Process)
|
reg := jobs.NewRegistry(wk.Process)
|
||||||
wk.Registry = reg
|
wk.Registry = reg
|
||||||
|
if pool != nil {
|
||||||
|
audit := repository.NewJobAuditWriter(pool)
|
||||||
|
reg.SetTerminalHook(func(j *jobs.Job) {
|
||||||
|
if j == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
st := j.Snapshot()
|
||||||
|
status, _ := st["status"].(string)
|
||||||
|
var errMsg *string
|
||||||
|
if e, ok := st["error"].(string); ok && e != "" {
|
||||||
|
errMsg = &e
|
||||||
|
}
|
||||||
|
audit.MarkTerminal(context.Background(), j.TenantID, j.ID, status, errMsg, time.Now().UTC())
|
||||||
|
})
|
||||||
|
}
|
||||||
observability.RegisterStoreBackend(backend)
|
observability.RegisterStoreBackend(backend)
|
||||||
return backend, reg, pool, nil
|
return backend, reg, pool, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ type Registry struct {
|
|||||||
byIdempo map[idempoKey]*Job
|
byIdempo map[idempoKey]*Job
|
||||||
workerStart func(j *Job)
|
workerStart func(j *Job)
|
||||||
workerSem chan struct{}
|
workerSem chan struct{}
|
||||||
|
onTerminal func(j *Job)
|
||||||
}
|
}
|
||||||
|
|
||||||
type idempoKey struct {
|
type idempoKey struct {
|
||||||
@@ -198,6 +199,28 @@ func NewRegistry(workerStart func(j *Job)) *Registry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTerminalHook registers a best-effort callback when jobs reach a terminal state.
|
||||||
|
func (r *Registry) SetTerminalHook(fn func(j *Job)) {
|
||||||
|
if r == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
r.onTerminal = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) fireTerminal(j *Job) {
|
||||||
|
if r == nil || j == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.mu.RLock()
|
||||||
|
fn := r.onTerminal
|
||||||
|
r.mu.RUnlock()
|
||||||
|
if fn != nil {
|
||||||
|
fn(j)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func registryMaxConcurrentJobs() int {
|
func registryMaxConcurrentJobs() int {
|
||||||
if n, err := strconv.Atoi(strings.TrimSpace(os.Getenv("EVOBGP_JOB_MAX_CONCURRENT"))); err == nil && n > 0 {
|
if n, err := strconv.Atoi(strings.TrimSpace(os.Getenv("EVOBGP_JOB_MAX_CONCURRENT"))); err == nil && n > 0 {
|
||||||
return n
|
return n
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ func (w *Worker) httpClient() *http.Client {
|
|||||||
func (w *Worker) Process(j *Job) {
|
func (w *Worker) Process(j *Job) {
|
||||||
defer func() {
|
defer func() {
|
||||||
observability.RecordJobTerminal(j.Kind, j.statusLocked())
|
observability.RecordJobTerminal(j.Kind, j.statusLocked())
|
||||||
|
if w != nil && w.Registry != nil {
|
||||||
|
w.Registry.fireTerminal(j)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if w == nil || w.Store == nil {
|
if w == nil || w.Store == nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user