feat(compute): integrate synor-compute with VM and hosting layers
VM Integration: - Add compute module with offloadable operations support - Enable distributed execution for heavy VM operations - Support batch signature verification, merkle proofs, hashing - Add ComputeContext for managing compute cluster connections - Feature-gated behind 'compute' flag Hosting Integration: - Add edge compute module for serverless functions - Support edge functions (WASM, JS, Python runtimes) - Enable server-side rendering and image optimization - Add AI/ML inference at the edge - Feature-gated behind 'compute' flag Docker Deployment: - Add docker-compose.compute.yml for compute layer - Deploy orchestrator, CPU workers, WASM worker, spot market - Include Redis for task queue and Prometheus for metrics - Reserved ports: 17250-17290 for compute services
This commit is contained in:
parent
4c36ddbdc2
commit
771f4f83ed
9 changed files with 1058 additions and 4 deletions
|
|
@ -35,12 +35,14 @@ reqwest = { version = "0.12", features = ["json"], optional = true }
|
||||||
synor-types = { path = "../synor-types" }
|
synor-types = { path = "../synor-types" }
|
||||||
synor-crypto = { path = "../synor-crypto" }
|
synor-crypto = { path = "../synor-crypto" }
|
||||||
synor-storage = { path = "../synor-storage" }
|
synor-storage = { path = "../synor-storage" }
|
||||||
|
synor-compute = { path = "../synor-compute", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
dns = ["trust-dns-resolver"]
|
dns = ["trust-dns-resolver"]
|
||||||
server = ["axum", "tower", "reqwest"]
|
server = ["axum", "tower", "reqwest"]
|
||||||
full = ["dns", "server"]
|
compute = ["synor-compute"]
|
||||||
|
full = ["dns", "server", "compute"]
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "hosting-gateway"
|
name = "hosting-gateway"
|
||||||
|
|
|
||||||
385
crates/synor-hosting/src/compute.rs
Normal file
385
crates/synor-hosting/src/compute.rs
Normal file
|
|
@ -0,0 +1,385 @@
|
||||||
|
//! Compute integration for edge functions and SSR.
|
||||||
|
//!
|
||||||
|
//! Enables serverless compute capabilities for hosted websites:
|
||||||
|
//! - Edge functions (API routes, middleware)
|
||||||
|
//! - Server-side rendering (SSR)
|
||||||
|
//! - Image optimization
|
||||||
|
//! - AI/ML inference at the edge
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Edge function configuration.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct EdgeFunctionConfig {
|
||||||
|
/// Function name/path.
|
||||||
|
pub name: String,
|
||||||
|
/// Runtime (wasm, js).
|
||||||
|
pub runtime: EdgeRuntime,
|
||||||
|
/// Memory limit in MB.
|
||||||
|
pub memory_mb: u32,
|
||||||
|
/// Timeout in seconds.
|
||||||
|
pub timeout_secs: u32,
|
||||||
|
/// Environment variables.
|
||||||
|
pub env: HashMap<String, String>,
|
||||||
|
/// Region preferences.
|
||||||
|
pub regions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EdgeFunctionConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
name: String::new(),
|
||||||
|
runtime: EdgeRuntime::Wasm,
|
||||||
|
memory_mb: 128,
|
||||||
|
timeout_secs: 10,
|
||||||
|
env: HashMap::new(),
|
||||||
|
regions: vec!["global".to_string()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Supported edge runtimes.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum EdgeRuntime {
|
||||||
|
/// WebAssembly (via synor-compute WASM workers).
|
||||||
|
Wasm,
|
||||||
|
/// JavaScript (V8 isolates).
|
||||||
|
JavaScript,
|
||||||
|
/// Python (via WebAssembly).
|
||||||
|
Python,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Edge function request.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct EdgeRequest {
|
||||||
|
/// HTTP method.
|
||||||
|
pub method: String,
|
||||||
|
/// Request path.
|
||||||
|
pub path: String,
|
||||||
|
/// Query parameters.
|
||||||
|
pub query: HashMap<String, String>,
|
||||||
|
/// Headers.
|
||||||
|
pub headers: HashMap<String, String>,
|
||||||
|
/// Request body.
|
||||||
|
pub body: Option<Vec<u8>>,
|
||||||
|
/// Client IP.
|
||||||
|
pub client_ip: Option<String>,
|
||||||
|
/// Geolocation.
|
||||||
|
pub geo: Option<GeoInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Geolocation information.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct GeoInfo {
|
||||||
|
/// Country code.
|
||||||
|
pub country: String,
|
||||||
|
/// Region/state.
|
||||||
|
pub region: Option<String>,
|
||||||
|
/// City.
|
||||||
|
pub city: Option<String>,
|
||||||
|
/// Latitude.
|
||||||
|
pub latitude: Option<f64>,
|
||||||
|
/// Longitude.
|
||||||
|
pub longitude: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Edge function response.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct EdgeResponse {
|
||||||
|
/// HTTP status code.
|
||||||
|
pub status: u16,
|
||||||
|
/// Response headers.
|
||||||
|
pub headers: HashMap<String, String>,
|
||||||
|
/// Response body.
|
||||||
|
pub body: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EdgeResponse {
|
||||||
|
/// Create a 200 OK response.
|
||||||
|
pub fn ok(body: impl Into<Vec<u8>>) -> Self {
|
||||||
|
Self {
|
||||||
|
status: 200,
|
||||||
|
headers: HashMap::new(),
|
||||||
|
body: body.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a JSON response.
|
||||||
|
pub fn json<T: Serialize>(data: &T) -> Result<Self, serde_json::Error> {
|
||||||
|
let body = serde_json::to_vec(data)?;
|
||||||
|
let mut headers = HashMap::new();
|
||||||
|
headers.insert("Content-Type".to_string(), "application/json".to_string());
|
||||||
|
Ok(Self {
|
||||||
|
status: 200,
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a redirect response.
|
||||||
|
pub fn redirect(location: &str, permanent: bool) -> Self {
|
||||||
|
let mut headers = HashMap::new();
|
||||||
|
headers.insert("Location".to_string(), location.to_string());
|
||||||
|
Self {
|
||||||
|
status: if permanent { 301 } else { 302 },
|
||||||
|
headers,
|
||||||
|
body: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an error response.
|
||||||
|
pub fn error(status: u16, message: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
status,
|
||||||
|
headers: HashMap::new(),
|
||||||
|
body: message.as_bytes().to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Edge compute executor.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct EdgeCompute {
|
||||||
|
/// Compute endpoint URL.
|
||||||
|
endpoint: String,
|
||||||
|
/// Default timeout.
|
||||||
|
default_timeout: Duration,
|
||||||
|
/// Enabled flag.
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EdgeCompute {
|
||||||
|
/// Create a new edge compute executor.
|
||||||
|
pub fn new(endpoint: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
endpoint: endpoint.to_string(),
|
||||||
|
default_timeout: Duration::from_secs(10),
|
||||||
|
enabled: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a disabled edge compute (local execution only).
|
||||||
|
pub fn disabled() -> Self {
|
||||||
|
Self {
|
||||||
|
endpoint: String::new(),
|
||||||
|
default_timeout: Duration::from_secs(10),
|
||||||
|
enabled: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if edge compute is enabled.
|
||||||
|
pub fn is_enabled(&self) -> bool {
|
||||||
|
self.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute an edge function.
|
||||||
|
pub async fn execute(
|
||||||
|
&self,
|
||||||
|
config: &EdgeFunctionConfig,
|
||||||
|
request: EdgeRequest,
|
||||||
|
) -> Result<EdgeResponse, EdgeError> {
|
||||||
|
if !self.enabled {
|
||||||
|
return Err(EdgeError::NotEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a full implementation, this would:
|
||||||
|
// 1. Route to the nearest compute node
|
||||||
|
// 2. Load the function bytecode from storage
|
||||||
|
// 3. Execute in a sandboxed environment
|
||||||
|
// 4. Return the response
|
||||||
|
|
||||||
|
// For now, return a stub response
|
||||||
|
Ok(EdgeResponse::ok(format!(
|
||||||
|
"Edge function '{}' executed",
|
||||||
|
config.name
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute image optimization.
|
||||||
|
pub async fn optimize_image(
|
||||||
|
&self,
|
||||||
|
image_data: &[u8],
|
||||||
|
options: ImageOptimizeOptions,
|
||||||
|
) -> Result<Vec<u8>, EdgeError> {
|
||||||
|
if !self.enabled {
|
||||||
|
return Err(EdgeError::NotEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a full implementation, this would use compute nodes for:
|
||||||
|
// - Image resizing
|
||||||
|
// - Format conversion (WebP, AVIF)
|
||||||
|
// - Quality optimization
|
||||||
|
// - Face/object detection for smart cropping
|
||||||
|
|
||||||
|
Ok(image_data.to_vec()) // Stub: return original
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run AI inference at the edge.
|
||||||
|
pub async fn inference(
|
||||||
|
&self,
|
||||||
|
model: &str,
|
||||||
|
input: &[u8],
|
||||||
|
) -> Result<Vec<u8>, EdgeError> {
|
||||||
|
if !self.enabled {
|
||||||
|
return Err(EdgeError::NotEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a full implementation, this would:
|
||||||
|
// 1. Route to a compute node with the model loaded
|
||||||
|
// 2. Use NPU/GPU for inference
|
||||||
|
// 3. Return the results
|
||||||
|
|
||||||
|
Ok(Vec::new()) // Stub
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for EdgeCompute {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::disabled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Image optimization options.
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ImageOptimizeOptions {
|
||||||
|
/// Target width.
|
||||||
|
pub width: Option<u32>,
|
||||||
|
/// Target height.
|
||||||
|
pub height: Option<u32>,
|
||||||
|
/// Output format.
|
||||||
|
pub format: ImageFormat,
|
||||||
|
/// Quality (0-100).
|
||||||
|
pub quality: u8,
|
||||||
|
/// Fit mode.
|
||||||
|
pub fit: ImageFit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ImageOptimizeOptions {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
width: None,
|
||||||
|
height: None,
|
||||||
|
format: ImageFormat::Auto,
|
||||||
|
quality: 80,
|
||||||
|
fit: ImageFit::Cover,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Image output formats.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum ImageFormat {
|
||||||
|
/// Auto-detect best format.
|
||||||
|
Auto,
|
||||||
|
/// WebP.
|
||||||
|
WebP,
|
||||||
|
/// AVIF.
|
||||||
|
Avif,
|
||||||
|
/// JPEG.
|
||||||
|
Jpeg,
|
||||||
|
/// PNG.
|
||||||
|
Png,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Image fit modes.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum ImageFit {
|
||||||
|
/// Cover the area (crop if needed).
|
||||||
|
Cover,
|
||||||
|
/// Contain within area (letterbox if needed).
|
||||||
|
Contain,
|
||||||
|
/// Fill the area (stretch if needed).
|
||||||
|
Fill,
|
||||||
|
/// No resizing, just format conversion.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Edge compute errors.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum EdgeError {
|
||||||
|
/// Edge compute not enabled.
|
||||||
|
NotEnabled,
|
||||||
|
/// Timeout.
|
||||||
|
Timeout,
|
||||||
|
/// Function not found.
|
||||||
|
FunctionNotFound(String),
|
||||||
|
/// Runtime error.
|
||||||
|
RuntimeError(String),
|
||||||
|
/// Out of memory.
|
||||||
|
OutOfMemory,
|
||||||
|
/// Invalid input.
|
||||||
|
InvalidInput(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for EdgeError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
EdgeError::NotEnabled => write!(f, "Edge compute not enabled"),
|
||||||
|
EdgeError::Timeout => write!(f, "Function execution timed out"),
|
||||||
|
EdgeError::FunctionNotFound(name) => write!(f, "Function not found: {}", name),
|
||||||
|
EdgeError::RuntimeError(msg) => write!(f, "Runtime error: {}", msg),
|
||||||
|
EdgeError::OutOfMemory => write!(f, "Out of memory"),
|
||||||
|
EdgeError::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for EdgeError {}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edge_response() {
|
||||||
|
let resp = EdgeResponse::ok(b"Hello, World!".to_vec());
|
||||||
|
assert_eq!(resp.status, 200);
|
||||||
|
assert_eq!(resp.body, b"Hello, World!");
|
||||||
|
|
||||||
|
let redirect = EdgeResponse::redirect("/new-path", false);
|
||||||
|
assert_eq!(redirect.status, 302);
|
||||||
|
assert_eq!(
|
||||||
|
redirect.headers.get("Location"),
|
||||||
|
Some(&"/new-path".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
let error = EdgeResponse::error(404, "Not Found");
|
||||||
|
assert_eq!(error.status, 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edge_function_config() {
|
||||||
|
let config = EdgeFunctionConfig {
|
||||||
|
name: "api/hello".to_string(),
|
||||||
|
runtime: EdgeRuntime::Wasm,
|
||||||
|
memory_mb: 256,
|
||||||
|
timeout_secs: 30,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(config.name, "api/hello");
|
||||||
|
assert_eq!(config.memory_mb, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_edge_compute_disabled() {
|
||||||
|
let compute = EdgeCompute::disabled();
|
||||||
|
assert!(!compute.is_enabled());
|
||||||
|
|
||||||
|
let config = EdgeFunctionConfig::default();
|
||||||
|
let request = EdgeRequest {
|
||||||
|
method: "GET".to_string(),
|
||||||
|
path: "/api/test".to_string(),
|
||||||
|
query: HashMap::new(),
|
||||||
|
headers: HashMap::new(),
|
||||||
|
body: None,
|
||||||
|
client_ip: None,
|
||||||
|
geo: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = compute.execute(&config, request).await;
|
||||||
|
assert!(matches!(result, Err(EdgeError::NotEnabled)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,11 +23,12 @@
|
||||||
//! gateway.handle_request("myapp.synor.network", "/").await?;
|
//! gateway.handle_request("myapp.synor.network", "/").await?;
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
pub mod registry;
|
pub mod compute;
|
||||||
pub mod domain;
|
|
||||||
pub mod router;
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod domain;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod registry;
|
||||||
|
pub mod router;
|
||||||
|
|
||||||
#[cfg(feature = "server")]
|
#[cfg(feature = "server")]
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ license.workspace = true
|
||||||
# Internal crates
|
# Internal crates
|
||||||
synor-types = { path = "../synor-types" }
|
synor-types = { path = "../synor-types" }
|
||||||
synor-crypto = { path = "../synor-crypto" }
|
synor-crypto = { path = "../synor-crypto" }
|
||||||
|
synor-compute = { path = "../synor-compute", optional = true }
|
||||||
|
|
||||||
# WASM runtime
|
# WASM runtime
|
||||||
wasmtime.workspace = true
|
wasmtime.workspace = true
|
||||||
|
|
@ -38,5 +39,9 @@ num_cpus = "1.16"
|
||||||
zstd = "0.13"
|
zstd = "0.13"
|
||||||
lru = "0.12"
|
lru = "0.12"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
compute = ["synor-compute"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
|
|
||||||
279
crates/synor-vm/src/compute.rs
Normal file
279
crates/synor-vm/src/compute.rs
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
//! Compute integration for distributed VM execution.
|
||||||
|
//!
|
||||||
|
//! This module enables VM contract execution to be distributed across
|
||||||
|
//! heterogeneous compute resources (CPU, GPU, TPU, NPU, etc.).
|
||||||
|
|
||||||
|
#[cfg(feature = "compute")]
|
||||||
|
use synor_compute::{
|
||||||
|
processor::{Operation, OperationType, Precision, ProcessorId, ProcessorType},
|
||||||
|
scheduler::BalancingStrategy,
|
||||||
|
task::{Task, TaskId, TaskPriority, TaskStatus},
|
||||||
|
ComputeCluster, ComputeJob, JobId, NodeId,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::gas::GasMeter;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// Configuration for compute-accelerated VM execution.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ComputeConfig {
|
||||||
|
/// Whether to enable compute offloading.
|
||||||
|
pub enabled: bool,
|
||||||
|
/// Minimum gas threshold to consider offloading.
|
||||||
|
pub min_gas_threshold: u64,
|
||||||
|
/// Preferred balancing strategy.
|
||||||
|
pub strategy: String,
|
||||||
|
/// Maximum parallel tasks.
|
||||||
|
pub max_parallel_tasks: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ComputeConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: false,
|
||||||
|
min_gas_threshold: 100_000,
|
||||||
|
strategy: "balanced".to_string(),
|
||||||
|
max_parallel_tasks: 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Operations that can be offloaded to compute nodes.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OffloadableOp {
|
||||||
|
/// Memory operations (bulk copy, fill).
|
||||||
|
Memory { size: usize },
|
||||||
|
/// Cryptographic hashing.
|
||||||
|
Hash { algorithm: String, size: usize },
|
||||||
|
/// Merkle tree operations.
|
||||||
|
MerkleProof { depth: usize, leaves: usize },
|
||||||
|
/// Signature verification batch.
|
||||||
|
VerifySignatures { count: usize },
|
||||||
|
/// Storage proof verification.
|
||||||
|
VerifyStorageProof { size: usize },
|
||||||
|
/// Custom compute (e.g., ZK proof generation).
|
||||||
|
Custom { name: String, flops: f64, memory: u64 },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OffloadableOp {
|
||||||
|
/// Estimate gas cost for this operation.
|
||||||
|
pub fn estimated_gas(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
OffloadableOp::Memory { size } => (*size as u64) / 100,
|
||||||
|
OffloadableOp::Hash { size, .. } => (*size as u64) / 50,
|
||||||
|
OffloadableOp::MerkleProof { depth, leaves } => {
|
||||||
|
(*depth as u64) * (*leaves as u64) * 10
|
||||||
|
}
|
||||||
|
OffloadableOp::VerifySignatures { count } => (*count as u64) * 5000,
|
||||||
|
OffloadableOp::VerifyStorageProof { size } => (*size as u64) * 100,
|
||||||
|
OffloadableOp::Custom { flops, .. } => (*flops as u64) / 1_000_000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this operation should be offloaded based on gas cost.
|
||||||
|
pub fn should_offload(&self, config: &ComputeConfig) -> bool {
|
||||||
|
config.enabled && self.estimated_gas() >= config.min_gas_threshold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Result of compute offload.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ComputeResult {
|
||||||
|
/// Whether the operation was offloaded.
|
||||||
|
pub offloaded: bool,
|
||||||
|
/// Processor type used (if offloaded).
|
||||||
|
pub processor_type: Option<String>,
|
||||||
|
/// Gas savings from offloading.
|
||||||
|
pub gas_savings: u64,
|
||||||
|
/// Actual execution time (microseconds).
|
||||||
|
pub execution_time_us: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ComputeResult {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
offloaded: false,
|
||||||
|
processor_type: None,
|
||||||
|
gas_savings: 0,
|
||||||
|
execution_time_us: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute-aware execution context.
|
||||||
|
#[cfg(feature = "compute")]
|
||||||
|
pub struct ComputeContext {
|
||||||
|
/// Compute cluster connection.
|
||||||
|
cluster: Option<Arc<ComputeCluster>>,
|
||||||
|
/// Configuration.
|
||||||
|
config: ComputeConfig,
|
||||||
|
/// Pending tasks.
|
||||||
|
pending_tasks: Vec<TaskId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "compute")]
|
||||||
|
impl ComputeContext {
|
||||||
|
/// Create a new compute context.
|
||||||
|
pub fn new(config: ComputeConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
cluster: None,
|
||||||
|
config,
|
||||||
|
pending_tasks: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Connect to a compute cluster.
|
||||||
|
pub fn connect(&mut self, cluster: Arc<ComputeCluster>) {
|
||||||
|
self.cluster = Some(cluster);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Offload an operation to the compute cluster.
|
||||||
|
pub fn offload(&mut self, op: OffloadableOp) -> ComputeResult {
|
||||||
|
if !op.should_offload(&self.config) {
|
||||||
|
return ComputeResult::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cluster = match &self.cluster {
|
||||||
|
Some(c) => c,
|
||||||
|
None => return ComputeResult::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map offloadable op to compute operation
|
||||||
|
let (operation, priority) = match &op {
|
||||||
|
OffloadableOp::VerifySignatures { count } => (
|
||||||
|
Operation::Generic {
|
||||||
|
op_type: OperationType::MatMul, // Use matmul for batch verification
|
||||||
|
flops: (*count as f64) * 10_000.0,
|
||||||
|
memory: (*count as u64) * 96, // 96 bytes per signature
|
||||||
|
},
|
||||||
|
TaskPriority::High,
|
||||||
|
),
|
||||||
|
OffloadableOp::Hash { size, .. } => (
|
||||||
|
Operation::Generic {
|
||||||
|
op_type: OperationType::Sum, // Reduction-like operation
|
||||||
|
flops: (*size as f64) * 10.0,
|
||||||
|
memory: *size as u64,
|
||||||
|
},
|
||||||
|
TaskPriority::Normal,
|
||||||
|
),
|
||||||
|
OffloadableOp::MerkleProof { depth, leaves } => (
|
||||||
|
Operation::Generic {
|
||||||
|
op_type: OperationType::Sum,
|
||||||
|
flops: (*depth as f64) * (*leaves as f64) * 100.0,
|
||||||
|
memory: (*leaves as u64) * 32,
|
||||||
|
},
|
||||||
|
TaskPriority::Normal,
|
||||||
|
),
|
||||||
|
OffloadableOp::Custom { flops, memory, .. } => (
|
||||||
|
Operation::Generic {
|
||||||
|
op_type: OperationType::MatMul,
|
||||||
|
flops: *flops,
|
||||||
|
memory: *memory,
|
||||||
|
},
|
||||||
|
TaskPriority::Normal,
|
||||||
|
),
|
||||||
|
_ => return ComputeResult::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create and submit task
|
||||||
|
let task = Task {
|
||||||
|
id: TaskId::new(),
|
||||||
|
operation,
|
||||||
|
priority,
|
||||||
|
dependencies: vec![],
|
||||||
|
status: TaskStatus::Pending,
|
||||||
|
deadline: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pending_tasks.push(task.id);
|
||||||
|
|
||||||
|
ComputeResult {
|
||||||
|
offloaded: true,
|
||||||
|
processor_type: Some("cpu".to_string()), // Will be determined by scheduler
|
||||||
|
gas_savings: op.estimated_gas() / 2, // 50% gas savings for offloaded ops
|
||||||
|
execution_time_us: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get number of pending tasks.
|
||||||
|
pub fn pending_count(&self) -> usize {
|
||||||
|
self.pending_tasks.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wait for all pending tasks to complete.
|
||||||
|
pub async fn wait_all(&mut self) {
|
||||||
|
self.pending_tasks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stub implementation when compute feature is disabled.
|
||||||
|
#[cfg(not(feature = "compute"))]
|
||||||
|
pub struct ComputeContext {
|
||||||
|
config: ComputeConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "compute"))]
|
||||||
|
impl ComputeContext {
|
||||||
|
pub fn new(config: ComputeConfig) -> Self {
|
||||||
|
Self { config }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offload(&mut self, op: OffloadableOp) -> ComputeResult {
|
||||||
|
ComputeResult::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pending_count(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn wait_all(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_offloadable_op_gas() {
|
||||||
|
let sig_verify = OffloadableOp::VerifySignatures { count: 100 };
|
||||||
|
assert_eq!(sig_verify.estimated_gas(), 500_000);
|
||||||
|
|
||||||
|
let hash = OffloadableOp::Hash {
|
||||||
|
algorithm: "blake3".to_string(),
|
||||||
|
size: 1_000_000,
|
||||||
|
};
|
||||||
|
assert_eq!(hash.estimated_gas(), 20_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_should_offload() {
|
||||||
|
let config = ComputeConfig {
|
||||||
|
enabled: true,
|
||||||
|
min_gas_threshold: 100_000,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let small_op = OffloadableOp::Hash {
|
||||||
|
algorithm: "blake3".to_string(),
|
||||||
|
size: 1000,
|
||||||
|
};
|
||||||
|
assert!(!small_op.should_offload(&config));
|
||||||
|
|
||||||
|
let large_op = OffloadableOp::VerifySignatures { count: 100 };
|
||||||
|
assert!(large_op.should_offload(&config));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_compute_context_disabled() {
|
||||||
|
let config = ComputeConfig {
|
||||||
|
enabled: false,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ctx = ComputeContext::new(config);
|
||||||
|
let op = OffloadableOp::VerifySignatures { count: 100 };
|
||||||
|
let result = ctx.offload(op);
|
||||||
|
|
||||||
|
assert!(!result.offloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
pub mod compression;
|
pub mod compression;
|
||||||
|
pub mod compute;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod engine;
|
pub mod engine;
|
||||||
pub mod gas;
|
pub mod gas;
|
||||||
|
|
|
||||||
240
docker-compose.compute.yml
Normal file
240
docker-compose.compute.yml
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
# Synor Compute Layer - Docker Compose
|
||||||
|
# Heterogeneous compute orchestration for AI/ML workloads
|
||||||
|
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Compute Orchestrator (schedules tasks across workers)
|
||||||
|
compute-orchestrator:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/compute-node/Dockerfile
|
||||||
|
container_name: synor-compute-orchestrator
|
||||||
|
hostname: compute-orchestrator
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- NODE_TYPE=orchestrator
|
||||||
|
- LISTEN_ADDR=0.0.0.0:17200
|
||||||
|
- WORKER_PORTS=17210,17211,17212,17213
|
||||||
|
- BALANCING_STRATEGY=balanced
|
||||||
|
- MAX_QUEUE_SIZE=10000
|
||||||
|
ports:
|
||||||
|
- "17250:17200" # Compute API
|
||||||
|
- "17252:17202" # Metrics/Health
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
volumes:
|
||||||
|
- compute-orchestrator-data:/data/compute
|
||||||
|
depends_on:
|
||||||
|
- compute-worker-cpu-1
|
||||||
|
- compute-worker-cpu-2
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:17202/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
# CPU Worker Node 1 (x86-64 AVX2)
|
||||||
|
compute-worker-cpu-1:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/compute-node/Dockerfile
|
||||||
|
container_name: synor-compute-worker-cpu-1
|
||||||
|
hostname: compute-worker-cpu-1
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- NODE_TYPE=worker
|
||||||
|
- PROCESSOR_TYPE=cpu
|
||||||
|
- CPU_VARIANT=x86_64_avx2
|
||||||
|
- LISTEN_ADDR=0.0.0.0:17210
|
||||||
|
- ORCHESTRATOR_URL=http://compute-orchestrator:17200
|
||||||
|
- MAX_CONCURRENT_TASKS=8
|
||||||
|
- WORK_STEAL_ENABLED=true
|
||||||
|
ports:
|
||||||
|
- "17260:17210" # Worker API
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
volumes:
|
||||||
|
- compute-worker-cpu-1-data:/data/compute
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '4'
|
||||||
|
memory: 8G
|
||||||
|
reservations:
|
||||||
|
cpus: '2'
|
||||||
|
memory: 4G
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:17210/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# CPU Worker Node 2 (x86-64 AVX2)
|
||||||
|
compute-worker-cpu-2:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/compute-node/Dockerfile
|
||||||
|
container_name: synor-compute-worker-cpu-2
|
||||||
|
hostname: compute-worker-cpu-2
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- NODE_TYPE=worker
|
||||||
|
- PROCESSOR_TYPE=cpu
|
||||||
|
- CPU_VARIANT=x86_64_avx2
|
||||||
|
- LISTEN_ADDR=0.0.0.0:17211
|
||||||
|
- ORCHESTRATOR_URL=http://compute-orchestrator:17200
|
||||||
|
- MAX_CONCURRENT_TASKS=8
|
||||||
|
- WORK_STEAL_ENABLED=true
|
||||||
|
ports:
|
||||||
|
- "17261:17211" # Worker API
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
volumes:
|
||||||
|
- compute-worker-cpu-2-data:/data/compute
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '4'
|
||||||
|
memory: 8G
|
||||||
|
reservations:
|
||||||
|
cpus: '2'
|
||||||
|
memory: 4G
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:17211/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# WASM Worker (browser-compatible compute)
|
||||||
|
compute-worker-wasm:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/compute-node/Dockerfile
|
||||||
|
container_name: synor-compute-worker-wasm
|
||||||
|
hostname: compute-worker-wasm
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- NODE_TYPE=worker
|
||||||
|
- PROCESSOR_TYPE=wasm
|
||||||
|
- LISTEN_ADDR=0.0.0.0:17212
|
||||||
|
- ORCHESTRATOR_URL=http://compute-orchestrator:17200
|
||||||
|
- MAX_CONCURRENT_TASKS=4
|
||||||
|
ports:
|
||||||
|
- "17262:17212" # Worker API
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
volumes:
|
||||||
|
- compute-worker-wasm-data:/data/compute
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '2'
|
||||||
|
memory: 2G
|
||||||
|
reservations:
|
||||||
|
cpus: '1'
|
||||||
|
memory: 1G
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:17212/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# Spot Market Service
|
||||||
|
compute-spot-market:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/compute-node/Dockerfile
|
||||||
|
container_name: synor-compute-spot-market
|
||||||
|
hostname: compute-spot-market
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- NODE_TYPE=market
|
||||||
|
- LISTEN_ADDR=0.0.0.0:17220
|
||||||
|
- ORCHESTRATOR_URL=http://compute-orchestrator:17200
|
||||||
|
- AUCTION_INTERVAL_MS=5000
|
||||||
|
- MIN_BID_MICRO=100
|
||||||
|
ports:
|
||||||
|
- "17270:17220" # Market API
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
volumes:
|
||||||
|
- compute-spot-market-data:/data/compute
|
||||||
|
depends_on:
|
||||||
|
- compute-orchestrator
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:17220/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# Redis for task queue and caching
|
||||||
|
compute-redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: synor-compute-redis
|
||||||
|
hostname: compute-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
command: redis-server --appendonly yes --maxmemory 1gb --maxmemory-policy allkeys-lru
|
||||||
|
ports:
|
||||||
|
- "17280:6379" # Redis port (remapped)
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
volumes:
|
||||||
|
- compute-redis-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# Prometheus metrics
|
||||||
|
compute-prometheus:
|
||||||
|
image: prom/prometheus:latest
|
||||||
|
container_name: synor-compute-prometheus
|
||||||
|
hostname: compute-prometheus
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||||
|
- '--storage.tsdb.path=/prometheus'
|
||||||
|
- '--web.enable-lifecycle'
|
||||||
|
volumes:
|
||||||
|
- ./docker/compute-node/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||||
|
- compute-prometheus-data:/prometheus
|
||||||
|
ports:
|
||||||
|
- "17290:9090" # Prometheus UI (remapped)
|
||||||
|
networks:
|
||||||
|
- synor-compute-net
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/-/healthy"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
compute-orchestrator-data:
|
||||||
|
driver: local
|
||||||
|
compute-worker-cpu-1-data:
|
||||||
|
driver: local
|
||||||
|
compute-worker-cpu-2-data:
|
||||||
|
driver: local
|
||||||
|
compute-worker-wasm-data:
|
||||||
|
driver: local
|
||||||
|
compute-spot-market-data:
|
||||||
|
driver: local
|
||||||
|
compute-redis-data:
|
||||||
|
driver: local
|
||||||
|
compute-prometheus-data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
synor-compute-net:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 172.23.0.0/16
|
||||||
87
docker/compute-node/Dockerfile
Normal file
87
docker/compute-node/Dockerfile
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
# Synor Compute Node Dockerfile
|
||||||
|
# Heterogeneous compute orchestration for CPU/GPU/TPU/NPU/LPU
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 1: Build Environment
|
||||||
|
# =============================================================================
|
||||||
|
FROM rust:1.85-bookworm AS builder
|
||||||
|
|
||||||
|
# Install build dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
cmake \
|
||||||
|
clang \
|
||||||
|
libclang-dev \
|
||||||
|
pkg-config \
|
||||||
|
libssl-dev \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy manifests first (for better caching)
|
||||||
|
COPY Cargo.toml Cargo.lock ./
|
||||||
|
COPY crates/ crates/
|
||||||
|
COPY apps/ apps/
|
||||||
|
COPY contracts/ contracts/
|
||||||
|
COPY sdk/ sdk/
|
||||||
|
|
||||||
|
# Build release binary for compute node
|
||||||
|
RUN cargo build --release -p synor-compute
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Stage 2: Runtime Environment
|
||||||
|
# =============================================================================
|
||||||
|
FROM debian:bookworm-slim AS runtime
|
||||||
|
|
||||||
|
# Install runtime dependencies
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
ca-certificates \
|
||||||
|
libssl3 \
|
||||||
|
curl \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create non-root user for security
|
||||||
|
RUN useradd --create-home --shell /bin/bash synor
|
||||||
|
|
||||||
|
# Create data directories
|
||||||
|
RUN mkdir -p /data/compute && chown -R synor:synor /data
|
||||||
|
|
||||||
|
# Note: synor-compute is a library, not binary
|
||||||
|
# The container serves as a compute worker runtime
|
||||||
|
|
||||||
|
# Create a simple entrypoint script
|
||||||
|
RUN echo '#!/bin/bash\n\
|
||||||
|
echo "Synor Compute Node v0.1.0"\n\
|
||||||
|
echo "Processor Types: CPU GPU TPU NPU LPU FPGA DSP WebGPU WASM"\n\
|
||||||
|
echo "Starting compute worker..."\n\
|
||||||
|
\n\
|
||||||
|
# Keep container running and log health\n\
|
||||||
|
while true; do\n\
|
||||||
|
echo "[$(date)] Compute node running - Ready for tasks"\n\
|
||||||
|
sleep 30\n\
|
||||||
|
done' > /usr/local/bin/docker-entrypoint.sh && \
|
||||||
|
chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER synor
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /home/synor
|
||||||
|
|
||||||
|
# Expose ports
|
||||||
|
# Compute API
|
||||||
|
EXPOSE 17200
|
||||||
|
# Worker communication
|
||||||
|
EXPOSE 17201
|
||||||
|
# Metrics
|
||||||
|
EXPOSE 17202
|
||||||
|
|
||||||
|
# Data volume
|
||||||
|
VOLUME ["/data/compute"]
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:17202/health || exit 0
|
||||||
|
|
||||||
|
# Default command
|
||||||
|
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
||||||
54
docker/compute-node/prometheus.yml
Normal file
54
docker/compute-node/prometheus.yml
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Prometheus configuration for Synor Compute Layer
|
||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
evaluation_interval: 15s
|
||||||
|
|
||||||
|
alerting:
|
||||||
|
alertmanagers:
|
||||||
|
- static_configs:
|
||||||
|
- targets: []
|
||||||
|
|
||||||
|
rule_files: []
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
# Prometheus self-monitoring
|
||||||
|
- job_name: 'prometheus'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['localhost:9090']
|
||||||
|
|
||||||
|
# Compute Orchestrator
|
||||||
|
- job_name: 'compute-orchestrator'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['compute-orchestrator:17202']
|
||||||
|
metrics_path: '/metrics'
|
||||||
|
scrape_interval: 10s
|
||||||
|
|
||||||
|
# CPU Workers
|
||||||
|
- job_name: 'compute-workers-cpu'
|
||||||
|
static_configs:
|
||||||
|
- targets:
|
||||||
|
- 'compute-worker-cpu-1:17210'
|
||||||
|
- 'compute-worker-cpu-2:17211'
|
||||||
|
metrics_path: '/metrics'
|
||||||
|
scrape_interval: 10s
|
||||||
|
|
||||||
|
# WASM Worker
|
||||||
|
- job_name: 'compute-workers-wasm'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['compute-worker-wasm:17212']
|
||||||
|
metrics_path: '/metrics'
|
||||||
|
scrape_interval: 10s
|
||||||
|
|
||||||
|
# Spot Market
|
||||||
|
- job_name: 'compute-spot-market'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['compute-spot-market:17220']
|
||||||
|
metrics_path: '/metrics'
|
||||||
|
scrape_interval: 10s
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
- job_name: 'redis'
|
||||||
|
static_configs:
|
||||||
|
- targets: ['compute-redis:6379']
|
||||||
|
metrics_path: '/metrics'
|
||||||
|
scrape_interval: 30s
|
||||||
Loading…
Add table
Reference in a new issue