@@ -23,6 +23,7 @@ import (
23
23
"code.gitea.io/gitea/modules/graceful"
24
24
"code.gitea.io/gitea/modules/hostmatcher"
25
25
"code.gitea.io/gitea/modules/log"
26
+ "code.gitea.io/gitea/modules/process"
26
27
"code.gitea.io/gitea/modules/proxy"
27
28
"code.gitea.io/gitea/modules/queue"
28
29
"code.gitea.io/gitea/modules/setting"
@@ -43,7 +44,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
43
44
return
44
45
}
45
46
// There was a panic whilst delivering a hook...
46
- log .Error ("PANIC whilst trying to deliver webhook[%d] to %s Panic: %v\n Stacktrace: %s" , t .ID , w .URL , err , log .Stack (2 ))
47
+ log .Error ("PANIC whilst trying to deliver webhook task [%d] to webhook %s Panic: %v\n Stacktrace: %s" , t .ID , w .URL , err , log .Stack (2 ))
47
48
}()
48
49
49
50
t .IsDelivered = true
@@ -52,7 +53,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
52
53
53
54
switch w .HTTPMethod {
54
55
case "" :
55
- log .Info ("HTTP Method for webhook %d empty, setting to POST as default" , t . ID )
56
+ log .Info ("HTTP Method for webhook %s empty, setting to POST as default" , w . URL )
56
57
fallthrough
57
58
case http .MethodPost :
58
59
switch w .ContentType {
@@ -78,14 +79,14 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
78
79
case http .MethodGet :
79
80
u , err := url .Parse (w .URL )
80
81
if err != nil {
81
- return err
82
+ return fmt . Errorf ( "unable to deliver webhook task[%d] as cannot parse webhook url %s: %w" , t . ID , w . URL , err )
82
83
}
83
84
vals := u .Query ()
84
85
vals ["payload" ] = []string {t .PayloadContent }
85
86
u .RawQuery = vals .Encode ()
86
87
req , err = http .NewRequest ("GET" , u .String (), nil )
87
88
if err != nil {
88
- return err
89
+ return fmt . Errorf ( "unable to deliver webhook task[%d] as unable to create HTTP request for webhook url %s: %w" , t . ID , w . URL , err )
89
90
}
90
91
case http .MethodPut :
91
92
switch w .Type {
@@ -97,13 +98,13 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
97
98
url := fmt .Sprintf ("%s/%s" , w .URL , url .PathEscape (txnID ))
98
99
req , err = http .NewRequest ("PUT" , url , strings .NewReader (t .PayloadContent ))
99
100
if err != nil {
100
- return err
101
+ return fmt . Errorf ( "unable to deliver webhook task[%d] as cannot create matrix request for webhook url %s: %w" , t . ID , w . URL , err )
101
102
}
102
103
default :
103
- return fmt .Errorf ("invalid http method for webhook: [%d] % v" , t .ID , w .HTTPMethod )
104
+ return fmt .Errorf ("invalid http method for webhook task [%d] in webhook %s: % v" , t .ID , w . URL , w .HTTPMethod )
104
105
}
105
106
default :
106
- return fmt .Errorf ("invalid http method for webhook: [%d] % v" , t .ID , w .HTTPMethod )
107
+ return fmt .Errorf ("invalid http method for webhook task [%d] in webhook %s: % v" , t .ID , w . URL , w .HTTPMethod )
107
108
}
108
109
109
110
var signatureSHA1 string
@@ -159,6 +160,20 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
159
160
Headers : map [string ]string {},
160
161
}
161
162
163
+ // OK We're now ready to attempt to deliver the task - we must double check that it
164
+ // has not been delivered in the meantime
165
+ updated , err := webhook_model .MarkTaskDelivered (ctx , t )
166
+ if err != nil {
167
+ log .Error ("MarkTaskDelivered[%d]: %v" , t .ID , err )
168
+ return fmt .Errorf ("unable to mark task[%d] delivered in the db: %w" , t .ID , err )
169
+ }
170
+ if ! updated {
171
+ // This webhook task has already been attempted to be delivered or is in the process of being delivered
172
+ log .Trace ("Webhook Task[%d] already delivered" , t .ID )
173
+ return nil
174
+ }
175
+
176
+ // All code from this point will update the hook task
162
177
defer func () {
163
178
t .Delivered = time .Now ().UnixNano ()
164
179
if t .IsSucceed {
@@ -190,13 +205,14 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
190
205
}
191
206
192
207
if ! w .IsActive {
208
+ log .Trace ("Webhook %s in Webhook Task[%d] is not active" , w .URL , t .ID )
193
209
return nil
194
210
}
195
211
196
212
resp , err := webhookHTTPClient .Do (req .WithContext (ctx ))
197
213
if err != nil {
198
214
t .ResponseInfo .Body = fmt .Sprintf ("Delivery: %v" , err )
199
- return err
215
+ return fmt . Errorf ( "unable to deliver webhook task[%d] in %s due to error in http client: %w" , t . ID , w . URL , err )
200
216
}
201
217
defer resp .Body .Close ()
202
218
@@ -210,7 +226,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error {
210
226
p , err := io .ReadAll (resp .Body )
211
227
if err != nil {
212
228
t .ResponseInfo .Body = fmt .Sprintf ("read body: %s" , err )
213
- return err
229
+ return fmt . Errorf ( "unable to deliver webhook task[%d] in %s as unable to read response body: %w" , t . ID , w . URL , err )
214
230
}
215
231
t .ResponseInfo .Body = string (p )
216
232
return nil
@@ -272,17 +288,37 @@ func Init() error {
272
288
}
273
289
go graceful .GetManager ().RunWithShutdownFns (hookQueue .Run )
274
290
275
- tasks , err := webhook_model .FindUndeliveredHookTasks (graceful .GetManager ().HammerContext ())
276
- if err != nil {
277
- log .Error ("FindUndeliveredHookTasks failed: %v" , err )
278
- return err
279
- }
291
+ go graceful .GetManager ().RunWithShutdownContext (populateWebhookSendingQueue )
292
+
293
+ return nil
294
+ }
295
+
296
+ func populateWebhookSendingQueue (ctx context.Context ) {
297
+ ctx , _ , finished := process .GetManager ().AddContext (ctx , "Webhook: Populate sending queue" )
298
+ defer finished ()
280
299
281
- for _ , task := range tasks {
282
- if err := enqueueHookTask (task ); err != nil {
283
- log .Error ("enqueueHookTask failed: %v" , err )
300
+ lowerID := int64 (0 )
301
+ for {
302
+ taskIDs , err := webhook_model .FindUndeliveredHookTaskIDs (ctx , lowerID )
303
+ if err != nil {
304
+ log .Error ("Unable to populate webhook queue as FindUndeliveredHookTaskIDs failed: %v" , err )
305
+ return
306
+ }
307
+ if len (taskIDs ) == 0 {
308
+ return
309
+ }
310
+ lowerID = taskIDs [len (taskIDs )- 1 ]
311
+
312
+ for _ , taskID := range taskIDs {
313
+ select {
314
+ case <- ctx .Done ():
315
+ log .Warn ("Shutdown before Webhook Sending queue finishing being populated" )
316
+ return
317
+ default :
318
+ }
319
+ if err := enqueueHookTask (taskID ); err != nil {
320
+ log .Error ("Unable to push HookTask[%d] to the Webhook Sending queue: %v" , taskID , err )
321
+ }
284
322
}
285
323
}
286
-
287
- return nil
288
324
}
0 commit comments