@@ -4,89 +4,80 @@ import (
44 "context"
55 "fmt"
66 "log/slog"
7- "net/http"
87 "os"
98 "time"
109
1110 "github.com/pior/runnable"
1211)
1312
14- func NewJobs () * Jobs {
15- return & Jobs {queue : make (chan string )}
16- }
17-
18- type Jobs struct {
19- queue chan string
20- }
21-
22- func (s * Jobs ) Perform (id string ) {
23- s .queue <- id
24- }
25-
26- // Run executes enqueued jobs, drains the queue and quits.
27- func (s * Jobs ) Run (ctx context.Context ) error {
28- for {
29- select {
30- case id := <- s .queue :
31- fmt .Printf ("Starting job %s\n " , id )
32- time .Sleep (time .Second )
33- fmt .Printf ("Completed job %s\n " , id )
34-
35- default :
36- if err := ctx .Err (); err != nil {
37- close (s .queue )
38- return err
13+ // exampleLogger returns a text logger writing to stdout without timestamps,
14+ // suitable for deterministic testable examples.
15+ func exampleLogger () * slog.Logger {
16+ return slog .New (slog .NewTextHandler (os .Stdout , & slog.HandlerOptions {
17+ ReplaceAttr : func (_ []string , a slog.Attr ) slog.Attr {
18+ if a .Key == slog .TimeKey {
19+ return slog.Attr {}
3920 }
40- }
41- }
21+ return a
22+ },
23+ }))
4224}
4325
44- type CleanupTask struct {}
26+ // JobQueue is a long-running service that processes background jobs.
27+ type JobQueue struct {}
4528
46- func (* CleanupTask ) Run (ctx context.Context ) error {
29+ func (q * JobQueue ) Run (ctx context.Context ) error {
4730 <- ctx .Done ()
4831 return nil
4932}
5033
51- func Example () {
52- runnable .SetLogger (slog .New (slog .NewTextHandler (os .Stdout , nil )))
53-
54- g := runnable .Manager ()
34+ func (q * JobQueue ) Enqueue (job string ) {
35+ fmt .Println ("JobQueue: " + job )
36+ }
5537
56- jobs := NewJobs ()
57- g .RegisterService (jobs )
38+ // CleanupTask enqueues a cleanup job on each execution.
39+ type CleanupTask struct {
40+ jobs * JobQueue
41+ runs int
42+ done chan struct {}
43+ }
5844
59- server := & http.Server {
60- Addr : "127.0.0.1:8080" ,
61- Handler : http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
62- id := r .URL .Query ().Get ("id" )
63- jobs .Perform (id )
64- }),
45+ func (t * CleanupTask ) Run (_ context.Context ) error {
46+ t .runs ++
47+ t .jobs .Enqueue (fmt .Sprintf ("cleanup-%d" , t .runs ))
48+ if t .runs >= 3 {
49+ close (t .done )
6550 }
66- g .Register (runnable .HTTPServer (server ))
51+ return nil
52+ }
6753
68- task := runnable .Func (func (ctx context.Context ) error {
69- _ , _ = http .Post ("http://127.0.0.1:8080/?id=1" , "test/plain" , nil )
70- _ , _ = http .Post ("http://127.0.0.1:8080/?id=2" , "test/plain" , nil )
71- _ , _ = http .Post ("http://127.0.0.1:8080/?id=3" , "test/plain" , nil )
54+ func Example () {
55+ runnable .SetLogger (exampleLogger ())
7256
73- return nil // quit right away, will trigger a shutdown
74- }). Name ( "enqueue" )
75- g . Register ( task )
57+ jobs := & JobQueue {}
58+ done := make ( chan struct {} )
59+ cleanup := & CleanupTask { jobs : jobs , done : done }
7660
77- cleanup := runnable .Schedule (& CleanupTask {}, runnable .Hourly ())
78- g .Register (cleanup )
61+ m := runnable .Manager ()
62+ m .RegisterService (jobs )
63+ m .Register (runnable .Schedule (cleanup , runnable .Every (500 * time .Millisecond )))
64+ m .Register (runnable .Func (func (_ context.Context ) error {
65+ <- done
66+ return nil
67+ }).Name ("app" ))
7968
80- runnable .Run (g )
69+ runnable .Run (m )
8170
82- // level=INFO msg="manager/Jobs: started"
83- // level=INFO msg="manager/httpserver: started"
84- // level=INFO msg="manager/enqueue: started"
71+ // Output:
72+ // level=INFO msg="manager/JobQueue: started"
8573 // level=INFO msg="manager/schedule/CleanupTask: started"
86- // level=INFO msg="httpserver: listening" addr=127.0.0.1:8080
87- // Starting job 1
88- // Completed job 1
89- // ...
90- // level=INFO msg="manager: starting shutdown" reason="enqueue died"
74+ // level=INFO msg="manager/app: started"
75+ // JobQueue: cleanup-1
76+ // JobQueue: cleanup-2
77+ // JobQueue: cleanup-3
78+ // level=INFO msg="manager/app: stopped"
79+ // level=INFO msg="manager: starting shutdown" reason="app died"
80+ // level=INFO msg="manager/schedule/CleanupTask: stopped"
81+ // level=INFO msg="manager/JobQueue: stopped"
9182 // level=INFO msg="manager: shutdown complete"
9283}
0 commit comments