Packages
honeydew
1.1.0
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
1.0.0-rc7
1.0.0-rc6
1.0.0-rc5
1.0.0-rc4
1.0.0-rc3
1.0.0-rc2
1.0.0-rc1
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
Pluggable local/clusterable job queue focused on safety.
Current section
Files
Jump to
Current section
Files
lib/honeydew/sources/ecto/sql.ex
defmodule Honeydew.EctoSource.SQL do
alias Honeydew.EctoSource.State
#
# you might be wondering "what's all this shitty sql for?", it's to make sure that the database is sole arbiter of "now",
# in case of clock skew between the various nodes running this queue
#
@type sql_fragment :: String.t()
@spec time_in_msecs_sql(sql_fragment) :: sql_fragment
def time_in_msecs_sql(time) do
"(EXTRACT('millisecond', (#{time})) + CAST((#{time}) AS INT) * 1000)"
end
@spec now_msecs_sql() :: sql_fragment
def now_msecs_sql do
time_in_msecs_sql("NOW()")
end
@spec msecs_ago_sql(sql_fragment | State.stale_timeout()) :: sql_fragment
def msecs_ago_sql(msecs) do
"#{now_msecs_sql()} - #{msecs}"
end
defmacro msecs_ago_fragment(msecs) do
sql = msecs_ago_sql("?")
quote do
fragment(unquote(sql), unquote(msecs))
end
end
# "I left in love, in laughter, and in truth. And wherever truth, love and laughter abide, I am there in spirit."
@spec far_in_the_past() :: NaiveDateTime.t()
def far_in_the_past do
~N[1994-03-26 04:20:00]
end
defmacro ready_fragment do
sql =
"CAST('#{far_in_the_past()}' AS TIMESTAMP)"
|> time_in_msecs_sql
|> msecs_ago_sql
quote do
fragment(unquote(sql))
end
end
@spec reserve_sql(State.t()) :: String.t()
def reserve_sql(state) do
"UPDATE #{state.table}
SET #{state.lock_field} = #{now_msecs_sql()}
WHERE #{state.lock_field} BETWEEN 0 AND #{msecs_ago_sql(state.stale_timeout)}
ORDER BY #{state.lock_field}, #{state.key_field}
LIMIT 1
RETURNING #{state.key_field}, #{state.private_field}"
end
@spec cancel_sql(State.t()) :: String.t()
def cancel_sql(state) do
"UPDATE #{state.table}
SET #{state.lock_field} = NULL
WHERE
id = $1
AND #{state.lock_field} BETWEEN 0 AND #{msecs_ago_sql(state.stale_timeout)}
LIMIT 1
RETURNING #{state.lock_field}"
end
end