From 0c168690a647eafa952dbc2b08f09f76864fafac Mon Sep 17 00:00:00 2001 From: Timur Gordon <31495328+timurgordon@users.noreply.github.com> Date: Tue, 4 Nov 2025 13:41:02 +0100 Subject: [PATCH] Use hero-job crate instead of local job module --- Cargo.lock | 18 ++ Cargo.toml | 2 + src/async_runner.rs | 2 +- src/client.rs | 462 -------------------------------------------- src/job.rs | 333 ------------------------------- src/lib.rs | 7 +- src/runner_trait.rs | 2 +- src/script_mode.rs | 2 +- src/sync_runner.rs | 2 +- 9 files changed, 26 insertions(+), 804 deletions(-) delete mode 100644 src/client.rs delete mode 100644 src/job.rs diff --git a/Cargo.lock b/Cargo.lock index f81edb2..e015edd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1283,6 +1283,23 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hero-job" +version = "0.1.0" +dependencies = [ + "chrono", + "hex", + "log", + "redis 0.25.4", + "secp256k1", + "serde", + "serde_json", + "sha2", + "thiserror 1.0.69", + "tokio", + "uuid", +] + [[package]] name = "hero_logger" version = "0.1.0" @@ -3244,6 +3261,7 @@ dependencies = [ "chrono", "clap", "env_logger", + "hero-job", "hero_logger", "heromodels", "heromodels-derive", diff --git a/Cargo.toml b/Cargo.toml index 4e6d780..792b057 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,8 @@ hex = "0.4" rand = "0.8" # Core hero dependencies hero_logger = { git = "https://git.ourworld.tf/herocode/baobab.git", branch = "logger" } +hero-job = { path = "../job/rust" } +# hero-job = { git = "https://git.ourworld.tf/herocode/job.git", subdirectory = "rust" } # Osiris dependencies (used by runner_osiris binary) osiris = { package = "osiris-core", path = "../osiris/core" } diff --git a/src/async_runner.rs b/src/async_runner.rs index 5ea35a8..d76335f 100644 --- a/src/async_runner.rs +++ b/src/async_runner.rs @@ -1,4 +1,4 @@ -use crate::job::Job; +use crate::Job; use log::{debug, error, info}; use rhai::{Engine, packages::Package}; use std::collections::HashMap; diff --git a/src/client.rs b/src/client.rs deleted file mode 100644 index c7f3ba1..0000000 --- a/src/client.rs +++ /dev/null @@ -1,462 +0,0 @@ -//! Job client implementation for managing jobs in Redis - -use chrono::Utc; -use redis::AsyncCommands; -use crate::job::{Job, JobStatus, JobError}; - -/// Client for managing jobs in Redis -#[derive(Debug, Clone)] -pub struct Client { - redis_client: redis::Client, - namespace: String, -} - -pub struct ClientBuilder { - /// Redis URL for connection - redis_url: String, - /// Namespace for queue keys - namespace: String, -} - -impl ClientBuilder { - /// Create a new client builder - pub fn new() -> Self { - Self { - redis_url: "redis://localhost:6379".to_string(), - namespace: "".to_string(), - } - } - - /// Set the Redis URL - pub fn redis_url>(mut self, url: S) -> Self { - self.redis_url = url.into(); - self - } - - /// Set the namespace for queue keys - pub fn namespace>(mut self, namespace: S) -> Self { - self.namespace = namespace.into(); - self - } - - /// Build the client - pub async fn build(self) -> Result { - // Create Redis client - let redis_client = redis::Client::open(self.redis_url.as_str()) - .map_err(|e| JobError::Redis(e))?; - - Ok(Client { - redis_client, - namespace: self.namespace, - }) - } -} - -impl Default for Client { - fn default() -> Self { - // Note: Default implementation creates an empty client - // Use Client::builder() for proper initialization - Self { - redis_client: redis::Client::open("redis://localhost:6379").unwrap(), - namespace: "".to_string(), - } - } -} - -impl Client { - /// Create a new client builder - pub fn builder() -> ClientBuilder { - ClientBuilder::new() - } - - /// List all job IDs from Redis - pub async fn list_jobs(&self) -> Result, JobError> { - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let keys: Vec = conn.keys(format!("{}:*", &self.jobs_key())).await - .map_err(|e| JobError::Redis(e))?; - let job_ids: Vec = keys - .into_iter() - .filter_map(|key| { - if key.starts_with(&format!("{}:", self.jobs_key())) { - key.strip_prefix(&format!("{}:", self.jobs_key())) - .map(|s| s.to_string()) - } else { - None - } - }) - .collect(); - - Ok(job_ids) - } - - fn jobs_key(&self) -> String { - if self.namespace.is_empty() { - format!("job") - } else { - format!("{}:job", self.namespace) - } - } - - pub fn job_key(&self, job_id: &str) -> String { - if self.namespace.is_empty() { - format!("job:{}", job_id) - } else { - format!("{}:job:{}", self.namespace, job_id) - } - } - - pub fn job_reply_key(&self, job_id: &str) -> String { - if self.namespace.is_empty() { - format!("reply:{}", job_id) - } else { - format!("{}:reply:{}", self.namespace, job_id) - } - } - - pub fn runner_key(&self, runner_name: &str) -> String { - if self.namespace.is_empty() { - format!("runner:{}", runner_name) - } else { - format!("{}:runner:{}", self.namespace, runner_name) - } - } - - /// Set job error in Redis - pub async fn set_error(&self, - job_id: &str, - error: &str, - ) -> Result<(), JobError> { - let job_key = self.job_key(job_id); - let now = Utc::now(); - - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let _: () = conn.hset_multiple(&job_key, &[ - ("error", error), - ("status", JobStatus::Error.as_str()), - ("updated_at", &now.to_rfc3339()), - ]).await - .map_err(|e| JobError::Redis(e))?; - - Ok(()) - } - - /// Set job status in Redis - pub async fn set_job_status(&self, - job_id: &str, - status: JobStatus, - ) -> Result<(), JobError> { - let job_key = self.job_key(job_id); - let now = Utc::now(); - - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let _: () = conn.hset_multiple(&job_key, &[ - ("status", status.as_str()), - ("updated_at", &now.to_rfc3339()), - ]).await - .map_err(|e| JobError::Redis(e))?; - Ok(()) - } - - /// Get job status from Redis - pub async fn get_status( - &self, - job_id: &str, - ) -> Result { - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let status_str: Option = conn.hget(&self.job_key(job_id), "status").await - .map_err(|e| JobError::Redis(e))?; - - match status_str { - Some(s) => JobStatus::from_str(&s).ok_or_else(|| JobError::InvalidStatus(s)), - None => Err(JobError::NotFound(job_id.to_string())), - } - } - - /// Delete job from Redis - pub async fn delete_from_redis( - &self, - job_id: &str, - ) -> Result<(), JobError> { - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let job_key = self.job_key(job_id); - let _: () = conn.del(&job_key).await - .map_err(|e| JobError::Redis(e))?; - Ok(()) - } - - /// Store this job in Redis with the specified status - pub async fn store_job_in_redis_with_status(&self, job: &Job, status: JobStatus) -> Result<(), JobError> { - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let job_key = self.job_key(&job.id); - - // Serialize the job data - let job_data = serde_json::to_string(job) - .map_err(|e| JobError::Serialization(e))?; - - // Store job data in Redis hash - let _: () = conn.hset_multiple(&job_key, &[ - ("data", job_data), - ("status", status.as_str().to_string()), - ("created_at", job.created_at.to_rfc3339()), - ("updated_at", job.updated_at.to_rfc3339()), - ]).await - .map_err(|e| JobError::Redis(e))?; - - // Set TTL for the job (24 hours) - let _: () = conn.expire(&job_key, 86400).await - .map_err(|e| JobError::Redis(e))?; - - Ok(()) - } - - /// Store this job in Redis (defaults to Dispatched status for backwards compatibility) - pub async fn store_job_in_redis(&self, job: &Job) -> Result<(), JobError> { - self.store_job_in_redis_with_status(job, JobStatus::Dispatched).await - } - - /// Load a job from Redis by ID - pub async fn load_job_from_redis( - &self, - job_id: &str, - ) -> Result { - let job_key = self.job_key(job_id); - - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - // Get job data from Redis - let job_data: Option = conn.hget(&job_key, "data").await - .map_err(|e| JobError::Redis(e))?; - - match job_data { - Some(data) => { - let job: Job = serde_json::from_str(&data) - .map_err(|e| JobError::Serialization(e))?; - Ok(job) - } - None => Err(JobError::NotFound(job_id.to_string())), - } - } - - /// Delete a job by ID - pub async fn delete_job(&mut self, job_id: &str) -> Result<(), JobError> { - let mut conn = self.redis_client.get_multiplexed_async_connection().await - .map_err(|e| JobError::Redis(e))?; - - let job_key = self.job_key(job_id); - let deleted_count: i32 = conn.del(&job_key).await - .map_err(|e| JobError::Redis(e))?; - - if deleted_count == 0 { - return Err(JobError::NotFound(job_id.to_string())); - } - - Ok(()) - } - - /// Set job result in Redis - pub async fn set_result( - &self, - job_id: &str, - result: &str, - ) -> Result<(), JobError> { - let job_key = self.job_key(&job_id); - let now = Utc::now(); - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - let _: () = conn.hset_multiple(&job_key, &[ - ("result", result), - ("status", JobStatus::Finished.as_str()), - ("updated_at", &now.to_rfc3339()), - ]).await - .map_err(|e| JobError::Redis(e))?; - - Ok(()) - } - - /// Get job result from Redis - pub async fn get_result( - &self, - job_id: &str, - ) -> Result, JobError> { - let job_key = self.job_key(job_id); - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - let result: Option = conn.hget(&job_key, "result").await - .map_err(|e| JobError::Redis(e))?; - Ok(result) - } - - /// Get job result from Redis - pub async fn get_error( - &self, - job_id: &str, - ) -> Result, JobError> { - let job_key = self.job_key(job_id); - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - let result: Option = conn.hget(&job_key, "error").await - .map_err(|e| JobError::Redis(e))?; - Ok(result) - } - - /// Get a job ID from the work queue (blocking pop) - pub async fn get_job_id(&self, queue_key: &str) -> Result, JobError> { - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - // Use BRPOP with a short timeout to avoid blocking indefinitely - let result: Option<(String, String)> = conn.brpop(queue_key, 1.0).await - .map_err(|e| JobError::Redis(e))?; - - Ok(result.map(|(_, job_id)| job_id)) - } - - /// Get a job by ID (alias for load_job_from_redis) - pub async fn get_job(&self, job_id: &str) -> Result { - self.load_job_from_redis(job_id).await - } - - /// Dispatch a job to a runner's queue - pub async fn dispatch_job(&self, job_id: &str, runner_name: &str) -> Result<(), JobError> { - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let queue_key = self.runner_key(runner_name); - - // Push job ID to the runner's queue (LPUSH for FIFO with BRPOP) - let _: () = conn.lpush(&queue_key, job_id).await - .map_err(|e| JobError::Redis(e))?; - - Ok(()) - } - - /// Run a job: dispatch it, wait for completion, and return the result - /// - /// This is a convenience method that: - /// 1. Stores the job in Redis - /// 2. Dispatches it to the runner's queue - /// 3. Waits for the job to complete (polls status) - /// 4. Returns the result or error - /// - /// # Arguments - /// * `job` - The job to run - /// * `runner_name` - The name of the runner to dispatch to - /// * `timeout_secs` - Maximum time to wait for job completion (in seconds) - /// - /// # Returns - /// * `Ok(String)` - The job result if successful - /// * `Err(JobError)` - If the job fails, times out, or encounters an error - pub async fn run_job( - &self, - job: &crate::job::Job, - runner_name: &str, - timeout_secs: u64, - ) -> Result { - use tokio::time::{Duration, timeout}; - - // Store the job in Redis - self.store_job_in_redis(job).await?; - - // Dispatch to runner queue - self.dispatch_job(&job.id, runner_name).await?; - - // Wait for job to complete with timeout - let result = timeout( - Duration::from_secs(timeout_secs), - self.wait_for_job_completion(&job.id) - ).await; - - match result { - Ok(Ok(job_result)) => Ok(job_result), - Ok(Err(e)) => Err(e), - Err(_) => Err(JobError::Timeout(format!( - "Job {} did not complete within {} seconds", - job.id, timeout_secs - ))), - } - } - - /// Wait for a job to complete by polling its status - /// - /// This polls the job status every 500ms until it reaches a terminal state - /// (Finished or Error), then returns the result or error. - async fn wait_for_job_completion(&self, job_id: &str) -> Result { - use tokio::time::{sleep, Duration}; - - loop { - // Check job status - let status = self.get_status(job_id).await?; - - match status { - JobStatus::Finished => { - // Job completed successfully, get the result - let result = self.get_result(job_id).await?; - return result.ok_or_else(|| { - JobError::InvalidData(format!("Job {} finished but has no result", job_id)) - }); - } - JobStatus::Error => { - // Job failed, get the error message - let mut conn = self.redis_client - .get_multiplexed_async_connection() - .await - .map_err(|e| JobError::Redis(e))?; - - let error_msg: Option = conn - .hget(&self.job_key(job_id), "error") - .await - .map_err(|e| JobError::Redis(e))?; - - return Err(JobError::InvalidData( - error_msg.unwrap_or_else(|| format!("Job {} failed with unknown error", job_id)) - )); - } - JobStatus::Stopping => { - return Err(JobError::InvalidData(format!("Job {} was stopped", job_id))); - } - // Job is still running (Dispatched, WaitingForPrerequisites, Started) - _ => { - // Wait before polling again - sleep(Duration::from_millis(500)).await; - } - } - } - } -} diff --git a/src/job.rs b/src/job.rs deleted file mode 100644 index 6374de6..0000000 --- a/src/job.rs +++ /dev/null @@ -1,333 +0,0 @@ -use chrono::{Utc}; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use thiserror::Error; -use uuid::Uuid; -use log::{error}; - -pub use crate::client::Client; - -/// Signature for a job - contains the signatory's public key and their signature -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct JobSignature { - /// Public key of the signatory (hex-encoded secp256k1 public key) - pub public_key: String, - /// Signature (hex-encoded secp256k1 signature) - pub signature: String, -} - -/// Job status enumeration -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum JobStatus { - Created, - Dispatched, - WaitingForPrerequisites, - Started, - Error, - Stopping, - Finished, -} - -impl JobStatus { - pub fn as_str(&self) -> &'static str { - match self { - JobStatus::Created => "created", - JobStatus::Dispatched => "dispatched", - JobStatus::WaitingForPrerequisites => "waiting_for_prerequisites", - JobStatus::Started => "started", - JobStatus::Error => "error", - JobStatus::Stopping => "stopping", - JobStatus::Finished => "finished", - } - } - - pub fn from_str(s: &str) -> Option { - match s { - "created" => Some(JobStatus::Created), - "dispatched" => Some(JobStatus::Dispatched), - "waiting_for_prerequisites" => Some(JobStatus::WaitingForPrerequisites), - "started" => Some(JobStatus::Started), - "error" => Some(JobStatus::Error), - "stopping" => Some(JobStatus::Stopping), - "finished" => Some(JobStatus::Finished), - _ => None, - } - } -} - -/// Representation of a script execution request. -/// -/// This structure contains all the information needed to execute a script -/// on a actor service, including the script content, dependencies, and metadata. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Job { - pub id: String, - pub caller_id: String, - pub context_id: String, - pub payload: String, - pub runner: String, // name of the runner to execute this job - pub executor: String, // name of the executor the runner will use to execute this job - pub timeout: u64, // timeout in seconds - pub env_vars: HashMap, // environment variables for script execution - pub created_at: chrono::DateTime, - pub updated_at: chrono::DateTime, - - /// Signatures from authorized signatories (public keys are included in each signature) - pub signatures: Vec, -} - -/// Error types for job operations -#[derive(Error, Debug)] -pub enum JobError { - #[error("Redis error: {0}")] - Redis(#[from] redis::RedisError), - #[error("Serialization error: {0}")] - Serialization(#[from] serde_json::Error), - #[error("Job not found: {0}")] - NotFound(String), - #[error("Invalid job status: {0}")] - InvalidStatus(String), - #[error("Timeout error: {0}")] - Timeout(String), - #[error("Invalid job data: {0}")] - InvalidData(String), - #[error("Signature verification failed: {0}")] - SignatureVerificationFailed(String), - #[error("Unauthorized: {0}")] - Unauthorized(String), -} - -impl Job { - /// Create a new job with the given parameters - pub fn new( - caller_id: String, - context_id: String, - payload: String, - runner: String, - executor: String, - ) -> Self { - let now = Utc::now(); - Self { - id: Uuid::new_v4().to_string(), - caller_id, - context_id, - payload, - runner, - executor, - timeout: 300, // 5 minutes default - env_vars: HashMap::new(), - created_at: now, - updated_at: now, - signatures: Vec::new(), - } - } - - /// Get the canonical representation of the job for signing - /// This creates a deterministic string representation that can be hashed and signed - /// Note: Signatures are excluded from the canonical representation - pub fn canonical_representation(&self) -> String { - // Create a deterministic representation excluding signatures - // Sort env_vars keys for deterministic ordering - let mut env_vars_sorted: Vec<_> = self.env_vars.iter().collect(); - env_vars_sorted.sort_by_key(|&(k, _)| k); - - format!( - "{}:{}:{}:{}:{}:{}:{}:{:?}", - self.id, - self.caller_id, - self.context_id, - self.payload, - self.runner, - self.executor, - self.timeout, - env_vars_sorted - ) - } - - /// Get list of signatory public keys from signatures - pub fn signatories(&self) -> Vec { - self.signatures.iter() - .map(|sig| sig.public_key.clone()) - .collect() - } - - /// Verify that all signatures are valid - /// Returns Ok(()) if verification passes, Err otherwise - /// Empty signatures list is allowed - loop simply won't execute - pub fn verify_signatures(&self) -> Result<(), JobError> { - use secp256k1::{Message, PublicKey, Secp256k1, ecdsa::Signature}; - use sha2::{Sha256, Digest}; - - // Get the canonical representation and hash it - let canonical = self.canonical_representation(); - let mut hasher = Sha256::new(); - hasher.update(canonical.as_bytes()); - let hash = hasher.finalize(); - - let secp = Secp256k1::verification_only(); - let message = Message::from_digest_slice(&hash) - .map_err(|e| JobError::SignatureVerificationFailed(format!("Invalid message: {}", e)))?; - - // Verify each signature (if any) - for sig_data in &self.signatures { - // Decode public key - let pubkey_bytes = hex::decode(&sig_data.public_key) - .map_err(|e| JobError::SignatureVerificationFailed(format!("Invalid public key hex: {}", e)))?; - let pubkey = PublicKey::from_slice(&pubkey_bytes) - .map_err(|e| JobError::SignatureVerificationFailed(format!("Invalid public key: {}", e)))?; - - // Decode signature - let sig_bytes = hex::decode(&sig_data.signature) - .map_err(|e| JobError::SignatureVerificationFailed(format!("Invalid signature hex: {}", e)))?; - let signature = Signature::from_compact(&sig_bytes) - .map_err(|e| JobError::SignatureVerificationFailed(format!("Invalid signature: {}", e)))?; - - // Verify signature - secp.verify_ecdsa(&message, &signature, &pubkey) - .map_err(|e| JobError::SignatureVerificationFailed(format!("Signature verification failed: {}", e)))?; - } - - Ok(()) - } -} - -/// Builder for constructing job execution requests. -pub struct JobBuilder { - caller_id: String, - context_id: String, - payload: String, - runner: String, - executor: String, - timeout: u64, // timeout in seconds - env_vars: HashMap, - signatures: Vec, -} - -impl JobBuilder { - pub fn new() -> Self { - Self { - caller_id: "".to_string(), - context_id: "".to_string(), - payload: "".to_string(), - runner: "".to_string(), - executor: "".to_string(), - timeout: 300, // 5 minutes default - env_vars: HashMap::new(), - signatures: Vec::new(), - } - } - - /// Set the caller ID for this job - pub fn caller_id(mut self, caller_id: &str) -> Self { - self.caller_id = caller_id.to_string(); - self - } - - /// Set the context ID for this job - pub fn context_id(mut self, context_id: &str) -> Self { - self.context_id = context_id.to_string(); - self - } - - /// Set the payload (script content) for this job - pub fn payload(mut self, payload: &str) -> Self { - self.payload = payload.to_string(); - self - } - - /// Set the runner name for this job - pub fn runner(mut self, runner: &str) -> Self { - self.runner = runner.to_string(); - self - } - - /// Set the executor for this job - pub fn executor(mut self, executor: &str) -> Self { - self.executor = executor.to_string(); - self - } - - /// Set the timeout for job execution (in seconds) - pub fn timeout(mut self, timeout: u64) -> Self { - self.timeout = timeout; - self - } - - /// Set a single environment variable - pub fn env_var(mut self, key: &str, value: &str) -> Self { - self.env_vars.insert(key.to_string(), value.to_string()); - self - } - - /// Set multiple environment variables from a HashMap - pub fn env_vars(mut self, env_vars: HashMap) -> Self { - self.env_vars = env_vars; - self - } - - /// Clear all environment variables - pub fn clear_env_vars(mut self) -> Self { - self.env_vars.clear(); - self - } - - /// Add a signature (public key and signature) - pub fn signature(mut self, public_key: &str, signature: &str) -> Self { - self.signatures.push(JobSignature { - public_key: public_key.to_string(), - signature: signature.to_string(), - }); - self - } - - /// Set multiple signatures - pub fn signatures(mut self, signatures: Vec) -> Self { - self.signatures = signatures; - self - } - - /// Clear all signatures - pub fn clear_signatures(mut self) -> Self { - self.signatures.clear(); - self - } - - /// Build the job - pub fn build(self) -> Result { - if self.caller_id.is_empty() { - return Err(JobError::InvalidData("caller_id is required".to_string())); - } - if self.context_id.is_empty() { - return Err(JobError::InvalidData("context_id is required".to_string())); - } - if self.payload.is_empty() { - return Err(JobError::InvalidData("payload is required".to_string())); - } - if self.runner.is_empty() { - return Err(JobError::InvalidData("runner is required".to_string())); - } - if self.executor.is_empty() { - return Err(JobError::InvalidData("executor is required".to_string())); - } - - let mut job = Job::new( - self.caller_id, - self.context_id, - self.payload, - self.runner, - self.executor, - ); - - job.timeout = self.timeout; - job.env_vars = self.env_vars; - job.signatures = self.signatures; - - Ok(job) - } -} - -impl Default for JobBuilder { - fn default() -> Self { - Self::new() - } -} diff --git a/src/lib.rs b/src/lib.rs index 79b94df..2c3517c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,17 +3,14 @@ pub mod async_runner; pub mod sync_runner; pub mod runner_trait; pub mod script_mode; -pub mod job; -pub mod client; // Public exports for convenience pub use runner_trait::{Runner, RunnerConfig, spawn_runner}; pub use async_runner::{AsyncRunner, spawn_async_runner}; pub use sync_runner::{SyncRunner, SyncRunnerConfig, spawn_sync_runner}; -// Re-export job types from local job module -pub use job::{Job, JobStatus, JobError, JobBuilder}; -pub use client::{Client, ClientBuilder}; +// Re-export job types from hero-job crate +pub use hero_job::{Job, JobStatus, JobError, JobBuilder, JobSignature, Client, ClientBuilder}; pub use redis::AsyncCommands; use log::{error, info}; diff --git a/src/runner_trait.rs b/src/runner_trait.rs index f813ef3..89476aa 100644 --- a/src/runner_trait.rs +++ b/src/runner_trait.rs @@ -27,7 +27,7 @@ //! └───────────────┘ //! ``` -use crate::job::{Job, JobStatus, Client}; +use crate::{Job, JobStatus, Client}; use log::{debug, error, info}; use redis::AsyncCommands; diff --git a/src/script_mode.rs b/src/script_mode.rs index 585fa10..3aac475 100644 --- a/src/script_mode.rs +++ b/src/script_mode.rs @@ -1,6 +1,6 @@ use std::time::Duration; use tokio::time::timeout; -use crate::job::{JobBuilder, Client, JobStatus}; +use crate::{JobBuilder, Client, JobStatus}; use log::{info, error}; use tokio::sync::mpsc; use std::sync::Arc; diff --git a/src/sync_runner.rs b/src/sync_runner.rs index 05c38bc..0ef7056 100644 --- a/src/sync_runner.rs +++ b/src/sync_runner.rs @@ -1,4 +1,4 @@ -use crate::job::Job; +use crate::Job; use crate::runner_trait::Runner; use log::{debug, error, info}; use rhai::{Engine, Dynamic};