No matter how u twist and turn it u cant make a locking mechanism in Lua file module, its simply not atomic and u will get race condition, u can make the chances small but not remove them totally. The mkdir/rmdir Windows commands (and underlying api) are atomic on the other hand, they either fail or complete and return code indicates state so we can use them for making a locking mechanisms without race conditions.
Since lua doesnt have much of a "check attributes of files and directories" api (except in lfs) we need to keep your timeout mechanism with a separate file for overriding the lock in case of stale locks.
I also modified the backoff rest to be random for more gracefully backoff.
I typically use Lua module lfs for this but thats not a good idea here as its an external "c" module, so attached is my suggestion. I've tested it as far as I can with servers down
regards
dx
EDIT: Damn, the timeout mechanism will still have a race, what if we read the timeout file, find it stale and remove it, but in between another process has done the same - then we have a race. So, the timeout file should have a separate lock i guess..which again opens up for deadlocks lol
EDIT: Ops forgot to make the timeout file....
Code: Select all
local function lockdir(lockPath)
return os.execute("mkdir "..string.fixPath(lockPath, false).." 2> nul")
end
local function unlockdir(lockPath)
os.execute("rmdir "..string.fixPath(lockPath, false))
end
local function reserveActiveWindow()
local lockPath = getExecutionPath().."/../micromacro.lck"
local lock = lockdir(lockPath)
-- Wait for if other bot needs active window
local printed = false
while lock ~= 0 do
file = io.open(getExecutionPath().."/../micromacro.pid", "r");
if file then
raw = file:read() or ""
file:close()
apid, atime = string.match(raw,"pid:(.*) time:(.*)")
apid = tonumber(apid)
atime = tonumber(atime)
if apid == nil or apid == pid or os.time()-tonumber(atime) > 60 then
releaseActiveWindow()
else
if not printed then
printf("Waiting for another bot to release the active window.")
printed = true
else
printf(".")
end
end
end
yrest(math.random(3000))
lock = lockdir(lockPath)
end
if printed then printf("\n") end
end
local function releaseActiveWindow()
os.remove(getExecutionPath().."/../micromacro.pid")
unlockdir(getExecutionPath().."/../micromacro.lck")
end