- Improved auto-generated list/form/search views with priority fields, two-column form layout, statusbar widget, notebook for O2M fields - Enhanced fields_get with currency_field, compute, related metadata - Fixed session handling: handleSessionInfo/handleSessionCheck use real session from cookie instead of hardcoded values - Added read_progress_bar and activity_format RPC stubs - Improved bootstrap translations with lang_parameters - Added "contacts" to session modules list Server starts successfully: 14 modules, 93 models, 378 XML templates, 503 JS modules transpiled — all from local frontend/ directory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69 lines
1.4 KiB
Go
69 lines
1.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// CronJob defines a scheduled task.
|
|
type CronJob struct {
|
|
Name string
|
|
Interval time.Duration
|
|
Handler func(ctx context.Context, pool *pgxpool.Pool) error
|
|
running bool
|
|
}
|
|
|
|
// CronScheduler manages periodic jobs.
|
|
type CronScheduler struct {
|
|
jobs []*CronJob
|
|
mu sync.Mutex
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
// NewCronScheduler creates a new scheduler.
|
|
func NewCronScheduler() *CronScheduler {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
return &CronScheduler{ctx: ctx, cancel: cancel}
|
|
}
|
|
|
|
// Register adds a job to the scheduler.
|
|
func (s *CronScheduler) Register(job *CronJob) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.jobs = append(s.jobs, job)
|
|
}
|
|
|
|
// Start begins running all registered jobs.
|
|
func (s *CronScheduler) Start(pool *pgxpool.Pool) {
|
|
for _, job := range s.jobs {
|
|
go s.runJob(job, pool)
|
|
}
|
|
log.Printf("cron: started %d jobs", len(s.jobs))
|
|
}
|
|
|
|
// Stop cancels all running jobs.
|
|
func (s *CronScheduler) Stop() {
|
|
s.cancel()
|
|
}
|
|
|
|
func (s *CronScheduler) runJob(job *CronJob, pool *pgxpool.Pool) {
|
|
ticker := time.NewTicker(job.Interval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-s.ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
if err := job.Handler(s.ctx, pool); err != nil {
|
|
log.Printf("cron: %s error: %v", job.Name, err)
|
|
}
|
|
}
|
|
}
|
|
}
|