forked from txix-open/bgjob
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.go
More file actions
135 lines (115 loc) · 2.69 KB
/
Copy pathclient.go
File metadata and controls
135 lines (115 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package bgjob
import (
"context"
"crypto/rand"
"encoding/hex"
"fmt"
"time"
)
type Tx interface {
Job() Job
Update(ctx context.Context, id string, attempt int32, lastError string, nextRunAt int64) error
UpdateNextRun(ctx context.Context, id string, nextRunAt int64) error
UpdateArg(ctx context.Context, id string, arg []byte) error
Delete(ctx context.Context, id string) error
SaveInDlq(ctx context.Context, job Job) error
}
type Store interface {
Acquire(ctx context.Context, queue string, tx func(tx Tx) error) error
BulkInsert(ctx context.Context, jobs []Job) error
}
type Client struct {
store Store
}
func NewClient(store Store) *Client {
return &Client{
store: store,
}
}
func (c *Client) Enqueue(ctx context.Context, req EnqueueRequest) error {
return c.BulkEnqueue(ctx, []EnqueueRequest{req})
}
func (c *Client) BulkEnqueue(ctx context.Context, list []EnqueueRequest) error {
jobs, err := requestsToJobs(list)
if err != nil {
return err
}
err = c.store.BulkInsert(ctx, jobs)
if err == ErrJobAlreadyExist {
return err
}
if err != nil {
return fmt.Errorf("bulk insert: %w", err)
}
return nil
}
func (c *Client) Do(ctx context.Context, queue string, f func(ctx context.Context, job Job) Result) error {
err := c.store.Acquire(ctx, queue, func(tx Tx) error {
return c.jobTx(ctx, tx, f)
})
return err
}
func (c *Client) jobTx(ctx context.Context, tx Tx, f func(ctx context.Context, job Job) Result) error {
job := tx.Job()
job.Attempt++
result := f(ctx, job)
if result.complete {
err := tx.Delete(ctx, job.Id)
if err != nil {
return fmt.Errorf("delete job: %w", err)
}
}
if result.retry {
err := tx.Update(
ctx,
job.Id,
job.Attempt,
result.err.Error(),
timeNow().Add(result.retryDelay).Unix(),
)
if err != nil {
return fmt.Errorf("update job: %w", err)
}
}
if result.moveToDlq {
errorString := result.err.Error()
job.LastError = &errorString
err := tx.SaveInDlq(ctx, job)
if err != nil {
return fmt.Errorf("insert into dlq: %w", err)
}
err = tx.Delete(ctx, job.Id)
if err != nil {
return fmt.Errorf("delete job: %w", err)
}
}
if result.reschedule {
err := tx.UpdateNextRun(
ctx,
job.Id,
timeNow().Add(result.rescheduleDelay).Unix(),
)
if err != nil {
return fmt.Errorf("update job: %w", err)
}
}
if result.overrideArg {
err := tx.UpdateArg(ctx, job.Id, result.arg)
if err != nil {
return fmt.Errorf("update job arg: %w", err)
}
}
return nil
}
func nextId() (string, error) {
arr := make([]byte, 24)
_, err := rand.Read(arr)
if err != nil {
return "", fmt.Errorf("read rand: %w", err)
}
id := hex.EncodeToString(arr)
return id, nil
}
func timeNow() time.Time {
return time.Now().UTC()
}