mod.rs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. pub mod commands;
  2. pub mod ops;
  3. pub mod serve;
  4. pub mod session;
  5. use anyhow::Result;
  6. use crate::cli::TmuxCommands;
  7. use crate::config::{Config, NcclConfig, Node, Recipe};
  8. /// Manages tmux sessions for model inference across a DGX Spark cluster.
  9. #[derive(Clone)]
  10. pub struct TmuxManager {
  11. #[allow(dead_code)]
  12. pub session_prefix: String,
  13. }
  14. impl TmuxManager {
  15. /// Generates a namespaced session name for a recipe and node rank.
  16. /// Format: `{recipe_name}-{engine}-r{rank}`
  17. pub fn session_name(&self, recipe: &Recipe, rank: u32) -> String {
  18. let name = recipe.name.replace(' ', "_");
  19. format!("{}-{}-r{}", name, recipe.engine, rank)
  20. }
  21. /// Builds the list of `export` commands for NCCL environment variables.
  22. pub fn build_nccl_setup(&self, nccl: &NcclConfig) -> Vec<String> {
  23. vec![
  24. format!("export NCCL_IB_HCA=\"{}\"", nccl.ib_hca),
  25. format!("export NCCL_SOCKET_IFNAME=\"{}\"", nccl.socket_ifname),
  26. format!("export NCCL_IB_GID_INDEX={}", nccl.ib_gid_index),
  27. format!("export NCCL_IB_DISABLE={}", nccl.ib_disable),
  28. ]
  29. }
  30. /// Builds engine-specific host IP environment variable.
  31. pub fn build_host_ip_export(&self, engine: &str, node: &Node) -> Vec<String> {
  32. match engine {
  33. "vllm" => vec![format!("export VLLM_HOST_IP={}", node.ib_ip)],
  34. "sglang" => vec![format!("export SGLANG_WORKER_IP={}", node.ib_ip)],
  35. _ => vec![
  36. format!("export VLLM_HOST_IP={}", node.ib_ip),
  37. format!("export SGLANG_WORKER_IP={}", node.ib_ip),
  38. ],
  39. }
  40. }
  41. }
  42. /// Detailed health status of a tmux session.
  43. #[derive(Debug, Clone)]
  44. pub struct SessionHealth {
  45. pub session_exists: bool,
  46. pub process_alive: bool,
  47. pub gpu_ok: bool,
  48. pub api_ok: bool,
  49. }
  50. impl SessionHealth {
  51. pub fn is_healthy(&self) -> bool {
  52. self.session_exists && self.process_alive && self.gpu_ok && self.api_ok
  53. }
  54. #[allow(dead_code)]
  55. pub fn is_degraded(&self) -> bool {
  56. self.session_exists && !self.process_alive
  57. }
  58. }
  59. /// Top-level handler for all `cargo run tmux <subcommand>` commands.
  60. pub async fn handle_tmux(config: &Config, cmd: TmuxCommands, dry_run: bool) -> Result<()> {
  61. match cmd {
  62. TmuxCommands::Serve {
  63. recipe,
  64. cluster,
  65. skip_before_serve,
  66. } => {
  67. serve::tmux_serve(config, &recipe, &cluster, skip_before_serve, dry_run).await?;
  68. }
  69. TmuxCommands::Stop { recipe, cluster } => {
  70. ops::tmux_stop(config, &recipe, &cluster, dry_run).await?;
  71. }
  72. TmuxCommands::Status { recipe, cluster } => {
  73. ops::tmux_status(config, &recipe, &cluster, dry_run).await?;
  74. }
  75. TmuxCommands::Logs {
  76. recipe,
  77. follow,
  78. cluster,
  79. } => {
  80. ops::tmux_logs(config, &recipe, &cluster, follow, dry_run).await?;
  81. }
  82. TmuxCommands::Attach { recipe, cluster } => {
  83. ops::tmux_attach(config, &recipe, &cluster, dry_run).await?;
  84. }
  85. }
  86. Ok(())
  87. }