API
K8sDeputy.Deputy
— TypeDeputy(; shutdown_handler=nothing, shutdown_handler_timeout::Period=Second(5))
Construct an application Deputy
which provides health check endpoints.
Keywords
shutdown_handler
(optional): A zero-argument function which allows the user to provide a custom callback function for whenshutdown!(::Deputy)
is called.shutdown_handler_timeout::Period
(optional): Specifies the maximum execution duration of ashutdown_handler
.
K8sDeputy.serve!
— FunctionK8sDeputy.serve!(deputy::Deputy, [host], [port::Integer]; kwargs...) -> HTTP.Server
Starts a non-blocking HTTP.Server
responding to requests to deputy
health checks. The following health check endpoints are available:
/health/live
: Is the server is alive/running?/health/ready
: Is the server ready (hasreadied!(deputy)
been called)?
These endpoints will respond with HTTP status 200 OK
on success or 503 Service Unavailable
on failure.
Arguments
host
(optional): The address to listen to for incoming requests. Defaults toSockets.localhost
.port::Integer
(optional): The port to listen on. Defaults to the port number specified by the environmental variableDEPUTY_HEALTH_CHECK_PORT
, otherwise8081
.
Any kwargs
provided are passed to HTTP.serve!
.
K8sDeputy.readied!
— Functionreadied!(deputy::Deputy) -> Nothing
Mark the application as "ready". Sets the readiness endpoint to respond with successful responses.
K8sDeputy.shutdown!
— Functionshutdown!(deputy::Deputy) -> Nothing
Initiates a shutdown of the application by:
- Mark the application as shutting down ("non-live").
- Executing the deputy's
shutdown_handler
(if defined). - Exiting the current Julia process.
If a deputy.shutdown_handler
is defined it must complete within the deputy.shutdown_handler_timeout
or a warning will be logged and the Julia process will immediately exit. Any exceptions that occur in the deputy.shutdown_handler
will also be logged and result in the Julia process exiting.
A shutdown_handler
may optionally call exit
if a user wants to specify the exit status. By default shutdown!
uses an exit status of 1
.
K8sDeputy.graceful_terminator
— Functiongraceful_terminator(f; set_entrypoint::Bool=true) -> Nothing
Register a zero-argument function to be called when graceful_terminate
is called targeting this process. The user-defined function f
is expected to call exit
to terminate the Julia process. The graceful_terminator
function is only allowed to be called once within a Julia process.
Keywords
set_entrypoint::Bool
(optional): Sets the calling Julia process as the "entrypoint" to be targeted by default when runninggraceful_terminate
in another Julia process. Users who want to utilizegraceful_terminator
in multiple Julia processes should useset_entrypoint=false
and specify process IDs when callinggraceful_terminate
. Defaults totrue
.
Examples
app_status = AppStatus()
graceful_terminator(() -> shutdown!(app_status))
Kubernetes Setup
When using Kubernetes (K8s) you can enable graceful termination of a Julia process by defining a pod preStop
container hook. Typically, K8s initiates graceful termination via the TERM
signal but as Julia forcefully terminates when receiving this signal and Julia does not support user-defined signal handlers we utilize preStop
instead.
Using the supervise entrypoint
K8sDeputy provides a bash script in bin/superviser.sh
which handles the TERM
signal and sends the "terminate"
message to the graceful termination socket. This can be used as the ENTRYPOINT
for your Docker image. For example, after installing K8sDeputy
in the active Julia project:
RUN julia --color=yes -e 'using K8sDeputy; K8sDeputy.install_supervise_shim("/usr/bin")'
ENTRYPOINT ["/usr/bin/supervise.sh"]
The command/script to run and any arguments it requires should be passed in via args
in your K8s Container spec; anything you specify for command
in the Container spec will override the container's entrypoint.
The entrypoint script requires netcat
, which is not present in e.g. debian-slim
images. In particular, it requires the "OpenBSD" flavor (available as netcat-openbsd
via apt-get
). The script will fail before starting if command -v nc
fails.
It also uses jq
to generate JSON-formatted log messages with timestamps. This is not required (it uses a more fragile fallback) but strongly recommended.
Using the pre-stop hook
The following K8s pod manifest snippet will specify K8s to call the user-defined function specified by the graceful_terminator
:
spec:
containers:
- lifecycle:
preStop:
exec:
command: ["julia", "-e", "using K8sDeputy; graceful_terminate()"]
Additionally, the entrypoint for the container should also not directly use the Julia process as the init process (PID 1). Instead, users should define their entrypoint similarly to ["/bin/sh", "-c", "julia entrypoint.jl; sleep 1"]
as this allows for both the Julia process and the preStop
process to cleanly terminate.
K8sDeputy.graceful_terminate
— Functiongraceful_terminate(pid::Int32=entrypoint_pid(); wait::Bool=true) -> Nothing
Initiates the execution of the graceful_terminator
user callback in the process pid
. See graceful_terminator
for more details.