Packages
fnord
0.8.46
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/settings/file_lock.ex
defmodule Settings.FileLock do
@moduledoc """
Cross-process filesystem lock helpers for settings.json.
"""
@doc """
Acquire a lock directory alongside the JSON file at `path`.
Blocks up to `opts[:timeout_ms]` (default 10_000ms), treats locks older than
`opts[:stale_ms]` (default 120_000ms) as stale and reclaims them.
"""
@spec acquire_lock!(path :: binary, opts :: keyword) :: :ok
def acquire_lock!(path, opts \\ []) do
lock_dir = path <> ".lock"
timeout = Keyword.get(opts, :timeout_ms, 10_000)
stale = Keyword.get(opts, :stale_ms, 120_000)
start_time = System.monotonic_time(:millisecond)
do_acquire = fn fun ->
case File.mkdir(lock_dir) do
:ok ->
owner_info =
[
"pid: #{inspect(self())}",
"at: #{DateTime.utc_now() |> DateTime.to_iso8601()}"
]
|> Enum.join("\n")
File.write!(Path.join(lock_dir, "owner"), owner_info)
:ok
{:error, :eexist} ->
age_ms =
case File.stat(lock_dir) do
{:ok, %File.Stat{mtime: mtime}} ->
{{y, m, d}, {hh, mm, ss}} = mtime
file_secs = :calendar.datetime_to_gregorian_seconds({{y, m, d}, {hh, mm, ss}})
now_secs = System.os_time(:second)
(now_secs - file_secs) * 1_000
_ ->
stale + 1
end
if age_ms > stale do
File.rm_rf!(lock_dir)
fun.(fun)
else
elapsed = System.monotonic_time(:millisecond) - start_time
if elapsed >= timeout do
raise "Timeout acquiring file lock for #{path}\n" <>
"waited #{elapsed}ms (timeout is #{timeout}ms)"
else
:timer.sleep(50)
fun.(fun)
end
end
{:error, reason} ->
raise "Unable to create lock directory #{lock_dir}: #{inspect(reason)}"
end
end
do_acquire.(do_acquire)
end
@doc """
Release the lock directory created for `path`.
"""
@spec release_lock!(path :: binary) :: :ok
def release_lock!(path) do
lock_dir = path <> ".lock"
File.rm_rf!(lock_dir)
:ok
end
end