Packages
snakepit
0.9.0
0.13.0
0.12.0
0.11.1
0.11.0
0.10.1
0.10.0
0.9.1
0.9.0
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.11
0.6.10
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
High-performance pooler and session manager for external language integrations. Supports Python, Node.js, Ruby, and more with gRPC streaming, session management, and production-ready process cleanup.
Current section
Files
Jump to
Current section
Files
lib/snakepit/script_exit.ex
defmodule Snakepit.ScriptExit do
@moduledoc false
alias Snakepit.Logger, as: SLog
@type exit_mode :: :none | :halt | :stop | :auto
@type warning :: {:invalid_exit_env, String.t(), exit_mode()}
@exit_modes [:none, :halt, :stop, :auto]
@legacy_truthy ["1", "true", "yes", "y", "on"]
@spec resolve_exit_mode(keyword(), map()) :: {exit_mode(), [warning()]}
def resolve_exit_mode(opts, env) when is_list(opts) and is_map(env) do
if Keyword.has_key?(opts, :exit_mode) do
{validate_exit_mode!(Keyword.get(opts, :exit_mode)), []}
else
resolve_legacy_exit_mode(opts, env)
end
end
@spec resolve_auto_exit_mode(exit_mode(), boolean()) :: exit_mode()
def resolve_auto_exit_mode(:auto, owned?) do
resolve_auto_exit_mode(:auto, owned?, no_halt?())
end
def resolve_auto_exit_mode(exit_mode, _owned?), do: exit_mode
@spec resolve_auto_exit_mode(exit_mode(), boolean(), boolean()) :: exit_mode()
def resolve_auto_exit_mode(:auto, true, true), do: :stop
def resolve_auto_exit_mode(:auto, _owned?, _no_halt?), do: :none
def resolve_auto_exit_mode(exit_mode, _owned?, _no_halt?), do: exit_mode
@spec apply_exit_mode(exit_mode(), non_neg_integer()) :: :ok
def apply_exit_mode(:none, _status), do: :ok
def apply_exit_mode(:halt, status) when is_integer(status) do
System.halt(status)
end
def apply_exit_mode(:stop, status) when is_integer(status) do
System.stop(status)
Process.sleep(:infinity)
end
@spec log_warnings([warning()]) :: :ok
def log_warnings([]), do: :ok
def log_warnings(warnings) when is_list(warnings) do
Enum.each(warnings, &log_warning/1)
:ok
end
@spec no_halt?() :: boolean()
def no_halt? do
match?({:ok, _}, :init.get_argument(:no_halt))
end
@spec parse_script_exit_env(String.t() | nil) ::
{:ok, exit_mode()} | :unset | {:invalid, String.t()}
def parse_script_exit_env(nil), do: :unset
def parse_script_exit_env(value) when is_binary(value) do
trimmed = String.trim(value)
if trimmed == "" do
:unset
else
case String.downcase(trimmed) do
"none" -> {:ok, :none}
"halt" -> {:ok, :halt}
"stop" -> {:ok, :stop}
"auto" -> {:ok, :auto}
_ -> {:invalid, trimmed}
end
end
end
def parse_script_exit_env(_), do: :unset
@spec legacy_halt_truthy?(String.t() | nil) :: boolean()
def legacy_halt_truthy?(nil), do: false
def legacy_halt_truthy?(value) when is_binary(value) do
String.downcase(String.trim(value)) in @legacy_truthy
end
def legacy_halt_truthy?(_), do: false
defp resolve_legacy_exit_mode(opts, env) do
case Keyword.fetch(opts, :halt) do
{:ok, true} ->
{:halt, []}
{:ok, false} ->
resolve_env_exit_mode(env)
:error ->
resolve_env_exit_mode(env)
end
end
defp resolve_env_exit_mode(env) do
case parse_script_exit_env(Map.get(env, "SNAKEPIT_SCRIPT_EXIT")) do
{:ok, exit_mode} ->
{exit_mode, []}
:unset ->
resolve_legacy_halt_env(env)
{:invalid, value} ->
{fallback, _warnings} = resolve_legacy_halt_env(env)
{fallback, [{:invalid_exit_env, value, fallback}]}
end
end
defp resolve_legacy_halt_env(env) do
if legacy_halt_truthy?(Map.get(env, "SNAKEPIT_SCRIPT_HALT")) do
{:halt, []}
else
{:none, []}
end
end
defp validate_exit_mode!(exit_mode) when exit_mode in @exit_modes, do: exit_mode
defp validate_exit_mode!(exit_mode) do
raise ArgumentError,
"invalid exit_mode #{inspect(exit_mode)}; expected one of #{inspect(@exit_modes)}"
end
defp log_warning({:invalid_exit_env, value, fallback}) do
SLog.warning(
:shutdown,
"Invalid SNAKEPIT_SCRIPT_EXIT value #{inspect(value)}; using exit_mode #{fallback}.",
invalid_value: value,
fallback_exit_mode: fallback
)
end
end