Перейти к содержимому

Uzum - 2

Актуальность: Q1 2026

// Storage - persistent slow data store, methods can take >= 100ms
type storage interface {
GetTasks() ([]Task, error)
CompleteTasks(ctx context.Context, tasks []Task) error
AddBarcode(ctx context.Context, id, name string) (string, error)
UpdateProduct(id string, barcodeID string) error
}
type metrics interface {
CountExecutionDuration(process string, execTime float64)
}
type productsNotifier interface {
NotifyAboutChanges(productID string) error
}
type restClient interface {
GetBarcode(productID string) (string, string, error)
}
type Task struct {
ID string
ProductID string
Status string
}
type Transaction interface {
Start()
Finish() error
}
type Worker struct {
storage storage
restClient restClient
notify productsNotifier
metrics metrics
}
// The code is syntactically correct
// We use Go 1.24
// The service runs in k8s on 3 pods
// Processing is triggered every 30 seconds after the previous one completes on the pod (cron/supervisor + delay)
// REST client for getting barcode information from the tax authority
// Single interface for working with the DB
// In our service, the only external dependencies are PostgreSQL and NATS
// Agreement with another team to notify about any changes to Products entities
func (w *Worker) process(ctx context.Context) error {
defer w.metrics.CountExecutionDuration("barcode_tasks ", time.Since(time.Now()).Seconds())
tasks, err := w.storage.GetTasks() // query: select * from tasks where status = 'todo ';
if err != nil {
return err
}
eg, gctx := errGroup.WithContext(ctx)
for _, task := range tasks {
eg.Go(func() error {
return w.handleTask(ctx, task)
})
}
return w.storage.CompleteTasks(gctx, tasks) // query: update tasks set status = 'done 'where id in (:ids);
}
func (w *Worker) handleTask(ctx context.Context, task Task) error {
barcodeID, name, err := w.restClient.GetBarcode(task.ProductID)
if err != nil {
return err
}
id, err := w.storage.AddBarcode(ctx, barcodeID, name) // query: insert into barcodes(origin_id, name) values (:id, :name);
if err != nil {
return err
}
if err := w.storage.UpdateProduct(task.ProductID, id); err != nil { // query: update products set barcode_id = %s where id = %s;
return err
}
w.notify.NotifyAboutChanges(task.ProductID)
log.Info(fmt.Sprintf("barcode task for product id completed: %s ", task.ProductID))
return nil
}