@@ -416,17 +416,13 @@ end
416
416
---- --------------------------------------------------------------------------
417
417
418
418
419
- -- Run the given function holding a lock on the target.
420
- -- WARNING: the callback will run unprotected, so it should never
421
- -- throw an error, but always return `nil + error` instead.
422
- -- @param self The checker object
423
- -- @param ip Target IP
424
- -- @param port Target port
425
- -- @param hostname Target hostname
426
- -- @param fn The function to execute
427
- -- @return The results of the function; or nil and an error message
428
- -- in case it fails locking.
429
- local function locking_target (self , ip , port , hostname , fn )
419
+ --- Helper function to actually run the function holding a lock on the target.
420
+ -- @see locking_target
421
+ local function run_mutexed_fn (premature , self , ip , port , hostname , fn )
422
+ if premature then
423
+ return
424
+ end
425
+
430
426
local lock , lock_err = resty_lock :new (self .shm_name , {
431
427
exptime = 10 , -- timeout after which lock is released anyway
432
428
timeout = 5 , -- max wait time to acquire lock
@@ -436,20 +432,47 @@ local function locking_target(self, ip, port, hostname, fn)
436
432
end
437
433
local lock_key = key_for (self .TARGET_LOCK , ip , port , hostname )
438
434
439
- local ok , err = lock :lock (lock_key )
440
- if not ok then
441
- return nil , " failed to acquire lock: " .. err
435
+ local pok , perr = pcall (resty_lock .lock , lock , lock_key )
436
+ if not pok then
437
+ self :log (DEBUG , " failed to acquire lock: " , perr )
438
+ return nil , " failed to acquire lock"
442
439
end
443
440
444
441
local final_ok , final_err = fn ()
445
442
446
- ok , err = lock :unlock ()
443
+ local ok , err = lock :unlock ()
447
444
if not ok then
448
445
-- recoverable: not returning this error, only logging it
449
446
self :log (ERR , " failed to release lock '" , lock_key , " ': " , err )
450
447
end
451
448
452
449
return final_ok , final_err
450
+
451
+ end
452
+
453
+
454
+ -- Run the given function holding a lock on the target.
455
+ -- WARNING: the callback will run unprotected, so it should never
456
+ -- throw an error, but always return `nil + error` instead.
457
+ -- @param self The checker object
458
+ -- @param ip Target IP
459
+ -- @param port Target port
460
+ -- @param hostname Target hostname
461
+ -- @param fn The function to execute
462
+ -- @return The results of the function; or true in case it fails locking and
463
+ -- will retry asynchronously; or nil+err in case it fails to retry.
464
+ local function locking_target (self , ip , port , hostname , fn )
465
+ local ok , err = run_mutexed_fn (false , self , ip , port , hostname , fn )
466
+ if err == " failed to acquire lock" then
467
+ local _ , terr = ngx .timer .at (0 , run_mutexed_fn , self , ip , port , hostname , fn )
468
+ if terr ~= nil then
469
+ return nil , terr
470
+ end
471
+
472
+ return true
473
+ end
474
+
475
+ return ok , err
453
476
end
454
477
455
478
0 commit comments