gitdataai/apps/git-hook/src/main.rs
ZhenYi 7c042c7b9d
Some checks are pending
CI / Rust Lint & Check (push) Waiting to run
CI / Rust Tests (push) Waiting to run
CI / Frontend Lint & Type Check (push) Waiting to run
CI / Frontend Build (push) Blocked by required conditions
fix(git-hook): use HookService instead of non-existent GitServiceHooks
GitServiceHooks was renamed to HookService in the hook module refactor.
Updated main.rs to:
- Use HookService::new() with correct parameters (no http client)
- Call start_worker() which returns CancellationToken
- Wait on cancel.cancelled() instead of double-awaiting ctrl_c
- Clone token before moving into signal handler task
2026-04-17 13:54:17 +08:00

133 lines
3.7 KiB
Rust

use clap::Parser;
use config::AppConfig;
use db::cache::AppCache;
use db::database::AppDatabase;
use git::hook::HookService;
use slog::{Drain, OwnedKVList, Record};
use tokio::signal;
mod args;
use args::HookArgs;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// 1. Load configuration
let cfg = AppConfig::load();
// 2. Init slog logging
let log_level = cfg.log_level().unwrap_or_else(|_| "info".to_string());
let log = build_slog_logger(&log_level);
// 3. Connect to database
let db = AppDatabase::init(&cfg).await?;
slog::info!(log, "database connected");
// 4. Connect to Redis cache (also provides the cluster pool for hook queue)
let cache = AppCache::init(&cfg).await?;
slog::info!(log, "cache connected");
// 5. Parse CLI args
let _args = HookArgs::parse();
slog::info!(log, "git-hook worker starting");
// 6. Build and start git hook service
let hooks = HookService::new(
db,
cache.clone(),
cache.redis_pool().clone(),
log.clone(),
cfg,
);
let cancel = hooks.start_worker();
let cancel_signal = cancel.clone();
let log_clone = log.clone();
// Spawn signal handler that cancels on SIGINT/SIGTERM
tokio::spawn(async move {
let ctrl_c = async {
signal::ctrl_c()
.await
.expect("failed to install CTRL+C handler");
};
#[cfg(unix)]
let term = async {
use tokio::signal::unix::{SignalKind, signal};
let mut sig =
signal(SignalKind::terminate()).expect("failed to install SIGTERM handler");
sig.recv().await;
};
#[cfg(not(unix))]
let term = std::future::pending::<()>();
tokio::select! {
_ = ctrl_c => {
slog::info!(log_clone, "received SIGINT, initiating shutdown");
}
_ = term => {
slog::info!(log_clone, "received SIGTERM, initiating shutdown");
}
}
cancel_signal.cancel();
});
// Wait until the worker is cancelled (by signal handler or otherwise)
cancel.cancelled().await;
slog::info!(log, "git-hook worker stopped");
Ok(())
}
fn build_slog_logger(level: &str) -> slog::Logger {
let level_filter = match level {
"trace" => 0usize,
"debug" => 1usize,
"info" => 2usize,
"warn" => 3usize,
"error" => 4usize,
_ => 2usize,
};
struct StderrDrain(usize);
impl Drain for StderrDrain {
type Ok = ();
type Err = ();
#[inline]
fn log(&self, record: &Record, _logger: &OwnedKVList) -> Result<(), ()> {
let slog_level = match record.level() {
slog::Level::Trace => 0,
slog::Level::Debug => 1,
slog::Level::Info => 2,
slog::Level::Warning => 3,
slog::Level::Error => 4,
slog::Level::Critical => 5,
};
if slog_level < self.0 {
return Ok(());
}
let _ = eprintln!(
"{} [{}] {}:{} - {}",
chrono::Utc::now().format("%Y-%m-%dT%H:%M:%S%.3fZ"),
record.level().to_string(),
record
.file()
.rsplit_once('/')
.map(|(_, s)| s)
.unwrap_or(record.file()),
record.line(),
record.msg(),
);
Ok(())
}
}
let drain = StderrDrain(level_filter);
let drain = std::sync::Mutex::new(drain);
let drain = slog::Fuse::new(drain);
slog::Logger::root(drain, slog::o!())
}