feat: add /health endpoint on port 8091
All checks were successful
build-and-push-ext / build_push (push) Successful in 1m28s

- Add HTTP health server on port 8091
- Add CI workflow for dev4 branch with ext tag
- Health endpoint returns {"status":"ok"} for monitoring

ci: docker_tag=ext
This commit is contained in:
4NK Dev 2025-09-19 13:12:35 +00:00
parent a056d44cbf
commit 72bbffb31c
3 changed files with 136 additions and 0 deletions

View File

@ -0,0 +1,73 @@
name: build-and-push-ext
on:
push:
branches:
- dev4
jobs:
build_push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare SSH agent (optional)
shell: bash
run: |
set -euo pipefail
eval "$(ssh-agent -s)"
if [ -n "${{ secrets.SSH_PRIVATE_KEY || '' }}" ]; then
echo "${{ secrets.SSH_PRIVATE_KEY }}" | tr -d '\r' | ssh-add - >/dev/null 2>&1 || true
fi
mkdir -p ~/.ssh
ssh-keyscan git.4nkweb.com >> ~/.ssh/known_hosts 2>/dev/null || true
echo "SSH agent ready: $SSH_AUTH_SOCK"
# Rendre l'agent dispo aux steps suivants
echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> "$GITHUB_ENV"
echo "SSH_AGENT_PID=$SSH_AGENT_PID" >> "$GITHUB_ENV"
- name: Compute Docker tag from commit message or fallback
id: tag
shell: bash
run: |
set -euo pipefail
msg=$(git log -1 --pretty=%B)
if [[ "$msg" =~ ci:\ docker_tag=([a-zA-Z0-9._:-]+) ]]; then
tag="${BASH_REMATCH[1]}"
else
tag="dev-test"
fi
echo "TAG=$tag" | tee -a $GITHUB_OUTPUT
- name: Docker login (git.4nkweb.com)
shell: bash
env:
REG_USER: ${{ secrets.USER }}
REG_TOKEN: ${{ secrets.TOKEN }}
run: |
set -euo pipefail
echo "$REG_TOKEN" | docker login git.4nkweb.com -u "$REG_USER" --password-stdin
- name: Build image (target ext)
shell: bash
env:
DOCKER_BUILDKIT: "1"
run: |
set -euo pipefail
if [ -n "${SSH_AUTH_SOCK:-}" ]; then
docker build --ssh default \
-t git.4nkweb.com/4nk/sdk_relay:${{ steps.tag.outputs.TAG }} \
-f Dockerfile .
else
echo "SSH_AUTH_SOCK non défini: l'agent SSH n'est pas disponible. Assurez-vous de définir secrets.SSH_PRIVATE_KEY."
exit 1
fi
- name: Push image
shell: bash
run: |
set -euo pipefail
docker push git.4nkweb.com/4nk/sdk_relay:${{ steps.tag.outputs.TAG }}

37
docs/ANALYSE.md Normal file
View File

@ -0,0 +1,37 @@
## Analyse détaillée
### Périmètre
Service Rust `sdk_relay` interfaçant Bitcoin (RPC), Blindbit et WebSocket, avec configuration injectée.
### Stack
- **Langage**: Rust 2021
- **Dépendances**: `tokio`, `tokio-tungstenite`, `zeromq`, `bitcoincore-rpc`, `serde[_json]`, `env_logger`, `futures-util`, `sdk_common` (git, branche `dev`, features `parallel`, `blindbit-backend`).
### Build et image
- Docker multiétapes: build dans `rust:latest` avec SSH pour deps privées, exécution `debian:bookworm-slim`.
- Binaire: `/usr/local/bin/sdk_relay`.
- Conf: buildarg `CONF` écrit dans `/home/bitcoin/.conf`.
- Volumes: `/home/bitcoin/.4nk`, `/home/bitcoin/.bitcoin`.
### Réseau et healthcheck
- Ports: 8090, 8091 (exposés). Health: `GET /health` (via compose parent).
### Logs
- `RUST_LOG` géré par env; dans `lecoffre_node`, sortie tee vers `/home/bitcoin/.4nk/logs/sdk_relay.log`.
### Risques et points dattention
- Dépendance `sdk_common` via git/branche `dev`: geler par tag/commit pour reproductibilité.
- Image dexécution embarque `strace`; vérifier nécessité en prod.
- Permissions volume Windows: note de chown partiel dans compose parent.
### Actions proposées
- Pinner `sdk_common` sur un commit ou tag; documenter politique de mise à jour.
- Séparer images `-dev` et `-prod` si `strace` non requis.
- Documenter format du fichier de conf (`sdk_relay.conf`) et valeurs par défaut.

View File

@ -49,6 +49,7 @@ use tokio::net::{TcpListener, TcpStream};
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
use tokio_stream::wrappers::UnboundedReceiverStream;
use tokio_tungstenite::tungstenite::Message;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use anyhow::{Error, Result};
use zeromq::{Socket, SocketRecv};
@ -412,6 +413,28 @@ async fn handle_zmq(zmq_url: String, blindbit_url: String) {
}
}
async fn handle_health_endpoint(mut stream: TcpStream) {
let response = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 15\r\n\r\n{\"status\":\"ok\"}";
let _ = stream.write_all(response.as_bytes()).await;
let _ = stream.shutdown().await;
}
async fn start_health_server(port: u16) {
let listener = match TcpListener::bind(format!("0.0.0.0:{}", port)).await {
Ok(listener) => listener,
Err(e) => {
log::error!("Failed to bind health server on port {}: {}", port, e);
return;
}
};
log::info!("Health server listening on port {}", port);
while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(handle_health_endpoint(stream));
}
}
#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<()> {
env_logger::init();
@ -590,6 +613,9 @@ async fn main() -> Result<()> {
tokio::spawn(MessageCache::clean_up());
// Start health server on port 8091
tokio::spawn(start_health_server(8091));
// Let's spawn the handling of each connection in a separate task.
while let Ok((stream, addr)) = listener.accept().await {
tokio::spawn(handle_connection(stream, addr, our_sp_address));