use std::{ collections::BTreeMap, future::Future, net::TcpListener, pin::Pin, sync::{ Arc, atomic::{AtomicUsize, Ordering}, }, time::Duration, }; use actix_web::{App, HttpRequest, HttpResponse, HttpServer, http::header, web}; use futures_util::stream; use rcgen::{ BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, Issuer, KeyPair, KeyUsagePurpose, }; use remora_admission::{ AdmissionConfig, AdmissionDecision, AdmissionService, migrate as admission_migrate, }; use remora_api::{WorkerApiState, authenticate_rustls_worker, configure_worker_api}; use remora_attempt::{ ActivationOutcome, AttemptConfig, AttemptService, CheckpointRecord, DurableDescriptor, RecoveryConfig, StagingObject, migrate as attempt_migrate, }; use remora_contracts::{ CheckpointDescriptorRefDto, HttpSourceSubmissionDto, HuggingFaceRepositoryTypeDto, HuggingFaceSourceSubmissionDto, JobSubmissionDto, ObjectIdentityDto, ObjectStoreSourceSubmissionDto, PositiveIntegerDto, ProgressValueDto, ResolvedSourceDescriptorRefDto, ResultDescriptorDto, ResultKindDto, SafeIntegerDto, SourceProjectionDto, SourceSubmissionDto, }; use remora_coordination::{CoordinationStore, LeaseOwner, StoreConfig}; use remora_credentials::{ CreateCredential, CredentialRegistry, GrantBoundResolver, SecretMaterial, VaultClient, VaultConfig, migrate as credentials_migrate, }; use remora_domain::{BucketName, JobPhase, OpaqueId, StorageScope, TargetPrefix, TargetStoreId}; use remora_durable::{PoolConfig, connect, migrate as durable_migrate}; use remora_identity::{DefaultTarget, Principal}; use remora_outbound::OutboundPolicyBuilder; use remora_result::{ResultInventory, ResultMember, migrate as result_migrate}; use remora_stream::{CancelToken, CopyConfig, RetryTiming}; use remora_target::{CreateObjectRequest, TargetStore, TargetStoreConfig, attempt_manifest_key_in}; use remora_worker::{ AdapterExecutor, AttemptContext, AttemptExecution, AttemptExecutor, DescriptorStore, ObjectSourceEndpoint, WorkerApiClient, WorkerConfig, WorkerRunOutcome, WorkerRuntime, migrate as worker_migrate, }; use reqwest::{Certificate as ClientCertificate, Client, Identity}; use rustls::{ RootCertStore, ServerConfig, pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer}, server::WebPkiClientVerifier, }; use sha2::{Digest, Sha256}; use sqlx::PgPool; struct Harness { pool: PgPool, coordination: CoordinationStore, attempts: AttemptService, api: WorkerApiClient, owner: OpaqueId, server: actix_web::dev::ServerHandle, } impl Harness { async fn new(name: &str) -> Option { let database_url = required_env("DATABASE_URL")?; let coordination_url = required_env("REMORA_COORDINATION_URL")?; let pool = connect( &database_url, PoolConfig { max_connections: 24, acquire_timeout: Duration::from_secs(10), idle_timeout: Some(Duration::from_secs(30)), }, ) .await .unwrap(); durable_migrate(&pool).await.unwrap(); credentials_migrate(&pool).await.unwrap(); admission_migrate(&pool).await.unwrap(); attempt_migrate(&pool).await.unwrap(); result_migrate(&pool).await.unwrap(); worker_migrate(&pool).await.unwrap(); sqlx::query("TRUNCATE TABLE jobs CASCADE") .execute(&pool) .await .unwrap(); let coordination = CoordinationStore::connect( &coordination_url, format!("{}wp19:{name}:{}:", coordination_namespace(), nonce()), StoreConfig { global_limit: 16, lease_ttl: Duration::from_secs(2), reserve_ttl: Duration::from_secs(2), progress_ttl: Duration::from_secs(2), cancel_ttl: None, }, ) .await .unwrap(); let attempts = AttemptService::new( pool.clone(), coordination.clone(), AttemptConfig { max_attempts: 3, local_limit: 16, }, ) .unwrap(); let (base_url, server, client) = start_server(WorkerApiState::new(attempts.clone())).await; let api = WorkerApiClient::new(base_url, client).unwrap(); let owner = unique_id("owner"); Some(Self { pool, coordination, attempts, api, owner, server, }) } fn runtime(&self, executor: Arc) -> WorkerRuntime { WorkerRuntime::new( self.coordination.clone(), self.api.clone(), executor, WorkerConfig { local_limit: 2, idle_delay: Duration::from_millis(10), renew_interval: Duration::from_millis(200), cancel_poll_interval: Duration::from_millis(20), }, ) .unwrap() } async fn submit(&self, source: SourceSubmissionDto) -> OpaqueId { let store = TargetStoreId::parse( std::env::var("REMORA_TARGET_PROVIDER") .ok() .filter(|value| !value.is_empty() && value != "-") .as_deref() .unwrap_or("primary"), ) .unwrap(); let bucket = BucketName::parse( std::env::var("REMORA_TARGET_BUCKET") .ok() .filter(|value| !value.is_empty()) .as_deref() .unwrap_or("remora-results"), ) .unwrap(); let prefix = TargetPrefix::parse("users/alice", ["_remora"]).unwrap(); let principal = Principal { id: self.owner.clone(), issuer: "https://issuer.example".into(), subject: "subject".into(), administrator: false, scopes: [StorageScope { store: store.clone(), bucket: bucket.clone(), prefix: prefix.clone(), }] .into_iter() .collect(), }; let service = AdmissionService::new( self.pool.clone(), AdmissionConfig { default_target: DefaultTarget { store, bucket, prefix, }, reserved_target_segments: vec!["_remora".into()], policy_version: "worker-runtime-v1".into(), }, ) .unwrap(); let outcome = service .submit( &principal, unique_id("submit").as_str(), JobSubmissionDto { source, target: None, label: Some("worker-runtime-test".into()), }, ) .await .unwrap(); let job = match outcome.decision { AdmissionDecision::Accepted(job) => job, AdmissionDecision::Rejected { reason } => panic!("job rejected: {reason:?}"), }; self.coordination .enqueue(job.job_id.as_str()) .await .unwrap(); job.job_id } } impl Drop for Harness { fn drop(&mut self) { let server = self.server.clone(); tokio::spawn(async move { server.stop(true).await }); } } #[tokio::test] async fn all_source_kinds_run_through_activation_progress_checkpoint_and_outcome() { let Some(harness) = Harness::new("sources").await else { return; }; let executor = Arc::new(ProtocolExecutor::success(harness.pool.clone())); let runtime = harness.runtime(executor.clone()); let first_incarnation = runtime.incarnation().clone(); let restarted = harness.runtime(executor); assert_ne!(first_incarnation, *restarted.incarnation()); let sources = [ SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: "https://example.invalid/artifact?private=value".into(), result_path: "http.bin".into(), credential_id: None, }), SourceSubmissionDto::ObjectStore(ObjectStoreSourceSubmissionDto { store: "source-store".into(), bucket: "source-bucket".into(), key: "objects/item.bin".into(), version_id: Some("version-1".into()), result_path: "object.bin".into(), credential_id: None, }), SourceSubmissionDto::HuggingFace(HuggingFaceSourceSubmissionDto { repository_type: HuggingFaceRepositoryTypeDto::Model, repository_id: "owner/model".into(), revision: "0123456789abcdef0123456789abcdef01234567".into(), selection: None, credential_id: None, }), ]; for source in sources { let job_id = harness.submit(source).await; assert_eq!( runtime.run_once().await.unwrap(), WorkerRunOutcome::Succeeded ); let phase: String = sqlx::query_scalar("SELECT phase FROM jobs WHERE job_id = $1") .bind(job_id.as_str()) .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(phase, "succeeded"); assert!( harness .coordination .get_live_lease(job_id.as_str()) .await .unwrap() .is_none() ); } } #[tokio::test] async fn production_adapters_complete_one_job_per_source_kind() { let Some(harness) = Harness::new("production-sources").await else { return; }; let fixture = SourceFixture::start().await; let target_config = TargetStoreConfig::from_env().unwrap(); let target = TargetStore::connect(target_config.clone()).unwrap(); let source_key = CreateObjectRequest::for_attempt_object( &unique_id("sourceattempt"), &unique_id("sourceobject"), Some("source.bin"), ); let source_object = target .put_create_only(&source_key, SOURCE_BODY) .await .unwrap(); let (credential_id, resolver) = object_credential(&harness, false).await; let executor = production_executor(&harness, &fixture, resolver, target_config, "source-store"); let runtime = harness.runtime(executor); let sources = [ SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: format!("{}/http.bin", fixture.base_url), result_path: "http.bin".into(), credential_id: None, }), SourceSubmissionDto::ObjectStore(ObjectStoreSourceSubmissionDto { store: "source-store".into(), bucket: std::env::var("REMORA_TARGET_BUCKET").unwrap(), key: source_object.identity.key, version_id: None, result_path: "object.bin".into(), credential_id: Some(credential_id), }), SourceSubmissionDto::HuggingFace(HuggingFaceSourceSubmissionDto { repository_type: HuggingFaceRepositoryTypeDto::Model, repository_id: "owner/model".into(), revision: HF_COMMIT.into(), selection: None, credential_id: None, }), ]; for source in sources { let kind = match &source { SourceSubmissionDto::Http(_) => "http", SourceSubmissionDto::ObjectStore(_) => "object_store", SourceSubmissionDto::HuggingFace(_) => "hugging_face", }; let job_id = harness.submit(source).await; let outcome = runtime.run_once().await.unwrap(); if outcome != WorkerRunOutcome::Succeeded { let failure: Option = sqlx::query_scalar( "SELECT failure FROM attempts WHERE job_id = $1 ORDER BY fence DESC LIMIT 1", ) .bind(job_id.as_str()) .fetch_one(&harness.pool) .await .unwrap(); let inventory: Option<(String, i64, i64)> = sqlx::query_as( "SELECT i.state, i.member_count, i.total_bytes FROM result_inventories i JOIN attempts a ON a.attempt_id = i.attempt_id WHERE a.job_id = $1 ORDER BY a.fence DESC LIMIT 1", ) .bind(job_id.as_str()) .fetch_optional(&harness.pool) .await .unwrap(); panic!("{kind} failed with {outcome:?}: {failure:?}, inventory={inventory:?}"); } } } #[tokio::test] async fn production_adapter_resumes_a_transferred_checkpoint_after_restart() { let Some(harness) = Harness::new("production-resume").await else { return; }; let fixture = SourceFixture::start().await; let target_config = TargetStoreConfig::from_env().unwrap(); let target = TargetStore::connect(target_config.clone()).unwrap(); let source_url = format!("{}/http.bin", fixture.base_url); let job_id = harness .submit(SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: source_url.clone(), result_path: "http.bin".into(), credential_id: None, })) .await; assert_eq!( harness.coordination.dequeue().await.unwrap().as_deref(), Some(job_id.as_str()) ); let first_worker = unique_id("worker"); let first = match harness .attempts .claim(&job_id, &first_worker, &unique_id("claimop")) .await .unwrap() { remora_attempt::ClaimOutcome::Claimed { authority, .. } => authority, remora_attempt::ClaimOutcome::Rejected { reason, .. } => { panic!("initial claim rejected: {reason:?}") } }; assert!(matches!( harness .attempts .activate(&first, &unique_id("activateop")) .await .unwrap(), ActivationOutcome::Activated(_) )); let first = harness .attempts .authority(&first.attempt_id) .await .unwrap() .unwrap(); let descriptors = DescriptorStore::new(harness.pool.clone()); let identity = serde_json::json!({ "kind": "http", "requested_url_sha256": digest_text(&source_url), "final_url_sha256": digest_text(&source_url), "etag_sha256": digest_text("\"source-v1\""), "representation_length": SOURCE_BODY.len(), "content_encoding": "identity" }); let resolved_ref = descriptors .store_resolved(&first.attempt_id, &identity, Some(1)) .await .unwrap(); harness .attempts .pin_resolved_source( &first, &unique_id("resolveop"), resolved_descriptor(&resolved_ref), ) .await .unwrap(); let object_request = CreateObjectRequest::for_target_attempt_object( "users/alice", &first.attempt_id, &unique_id("member"), Some("http.bin"), ); let stored = target .put_create_only(&object_request, SOURCE_BODY) .await .unwrap(); let inventory = ResultInventory::new(harness.pool.clone()); inventory .create_bound(&first.attempt_id, &first.attempt_id, "users/alice") .await .unwrap(); inventory .add_member( &first.attempt_id, &ResultMember::new( unique_id("member"), "http.bin", stored.size, stored.identity.clone(), stored.content_sha256.clone(), ) .unwrap(), ) .await .unwrap(); harness .attempts .register_staging_object( &first.attempt_id, &StagingObject { target_store: stored.identity.target_store_id.clone(), bucket: stored.identity.bucket.clone(), key: stored.identity.key.clone(), version_id: stored.identity.version_id.clone(), }, ) .await .unwrap(); let checkpoint_ref = descriptors .store_checkpoint( &first.attempt_id, &serde_json::json!({ "staging_origin_attempt_id": first.attempt_id, "resolved_source_id": resolved_ref.id, "validated_bytes": SOURCE_BODY.len(), "validated_members": 1 }), Some(1), ) .await .unwrap(); harness .attempts .persist_checkpoint( &first, &unique_id("checkpointop"), CheckpointRecord { descriptor: checkpoint_descriptor(&checkpoint_ref), resolved_source_id: resolved_ref.id.clone(), validated_bytes: SOURCE_BODY.len() as u64, validated_members: 1, staging_multipart: None, }, ) .await .unwrap(); harness .attempts .publish_failure( &first, &unique_id("failureop"), remora_domain::RuntimeFailureClass::TransientTarget, ) .await .unwrap(); harness .coordination .release( job_id.as_str(), &LeaseOwner::new( first.attempt_id.as_str(), first.fence, first.worker_incarnation.as_str(), ) .unwrap(), ) .await .unwrap(); harness.attempts.release_local(&job_id); let recovery = RecoveryConfig { retry_delay: Duration::ZERO, ..RecoveryConfig::default() }; let report = harness.attempts.reconcile_once(&recovery).await.unwrap(); assert_eq!(report.retries_scheduled, 1); assert_eq!(report.enqueued, 1); let executor = production_executor( &harness, &fixture, object_credentialless_resolver(&harness).await, target_config, "source-store", ); let restarted = harness.runtime(executor); assert_ne!(first.worker_incarnation, *restarted.incarnation()); let outcome = restarted.run_once().await; if let Err(error) = &outcome { let job: (String, Option, Option) = sqlx::query_as( "SELECT phase, authority_attempt_id, checkpoint_owner_attempt_id FROM jobs WHERE job_id = $1", ) .bind(job_id.as_str()) .fetch_one(&harness.pool) .await .unwrap(); let attempts: Vec<(i64, String, String)> = sqlx::query_as( "SELECT fence, attempt_id, state FROM attempts WHERE job_id = $1 ORDER BY fence", ) .bind(job_id.as_str()) .fetch_all(&harness.pool) .await .unwrap(); panic!("resume failed with {error:?}; job={job:?}; attempts={attempts:?}"); } assert_eq!(outcome.unwrap(), WorkerRunOutcome::Succeeded); let attempts: Vec<(String, String)> = sqlx::query_as( "SELECT attempt_id, staging_origin_attempt_id FROM attempts WHERE job_id = $1 ORDER BY fence", ) .bind(job_id.as_str()) .fetch_all(&harness.pool) .await .unwrap(); assert_eq!(attempts.len(), 2); assert_eq!(attempts[1].1, attempts[0].0); let member: (String, String) = sqlx::query_as( "SELECT attempt_id, object_key FROM result_inventory_members WHERE path = 'http.bin'", ) .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(member.0, attempts[1].0); assert!( member .1 .starts_with(&format!("users/alice/_remora/a/{}/o/", attempts[0].0)) ); let cleanup_owner: String = sqlx::query_scalar("SELECT attempt_id FROM attempt_staging_cleanup WHERE object_key = $1") .bind(&member.1) .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(cleanup_owner, attempts[1].0); } #[tokio::test] async fn production_http_adapter_resumes_a_partial_multipart_after_process_loss() { let Some(harness) = Harness::new("production-partial-resume").await else { return; }; let fixture = SourceFixture::start().await; let target_config = TargetStoreConfig::from_env().unwrap(); let executor = production_executor( &harness, &fixture, object_credentialless_resolver(&harness).await, target_config, "source-store", ); let first = harness.runtime(executor.clone()); let first_incarnation = first.incarnation().clone(); let job_id = harness .submit(SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: format!("{}/large.bin", fixture.base_url), result_path: "large.bin".into(), credential_id: None, })) .await; let task = tokio::spawn(async move { first.run_once().await }); let partial = loop { let checkpoint: Option = sqlx::query_scalar("SELECT checkpoint FROM jobs WHERE job_id = $1") .bind(job_id.as_str()) .fetch_one(&harness.pool) .await .unwrap(); if let Some(checkpoint) = checkpoint.filter(|value| { value .pointer("/checkpoint/validated_members") .and_then(|value| value.as_u64()) == Some(0) }) { break checkpoint; } assert!( !task.is_finished(), "transfer finished before a partial checkpoint" ); tokio::time::sleep(Duration::from_millis(10)).await; }; assert_eq!( partial .pointer("/checkpoint/validated_bytes") .and_then(|value| value.as_u64()), Some(MULTIPART_BOUNDARY as u64) ); harness .coordination .drop_job_state(&[job_id.as_str()]) .await .unwrap(); assert_eq!( task.await.unwrap().unwrap(), WorkerRunOutcome::AuthorityLost ); let recovery = RecoveryConfig { retry_delay: Duration::ZERO, ..RecoveryConfig::default() }; assert_eq!( harness .attempts .reconcile_once(&recovery) .await .unwrap() .attempts_reaped, 1 ); let report = harness.attempts.reconcile_once(&recovery).await.unwrap(); assert_eq!(report.retries_scheduled, 1); assert_eq!(report.enqueued, 1); let restarted = harness.runtime(executor); assert_ne!(first_incarnation, *restarted.incarnation()); assert_eq!( restarted.run_once().await.unwrap(), WorkerRunOutcome::Succeeded ); assert_eq!(fixture.range_requests.load(Ordering::Acquire), 1); let attempts: Vec<(String, String)> = sqlx::query_as( "SELECT attempt_id, staging_origin_attempt_id FROM attempts WHERE job_id = $1 ORDER BY fence", ) .bind(job_id.as_str()) .fetch_all(&harness.pool) .await .unwrap(); assert_eq!(attempts.len(), 2); assert_eq!(attempts[1].1, attempts[0].0); let member: (String, String, i64) = sqlx::query_as( "SELECT attempt_id, object_key, size FROM result_inventory_members WHERE path = 'large.bin'", ) .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(member.0, attempts[1].0); assert_eq!(member.2, LARGE_SOURCE_SIZE as i64); assert!( member .1 .starts_with(&format!("users/alice/_remora/a/{}/o/", attempts[0].0)) ); let multipart_owner: String = sqlx::query_scalar( "SELECT attempt_id FROM attempt_staging_cleanup WHERE kind = 'multipart' ORDER BY cleanup_id DESC LIMIT 1", ) .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(multipart_owner, attempts[1].0); } #[tokio::test] async fn lease_loss_cancels_io_and_stale_authority_cannot_report() { let Some(harness) = Harness::new("lease-loss").await else { return; }; let executor = Arc::new(ProtocolExecutor::blocking(harness.pool.clone())); let runtime = harness.runtime(executor.clone()); let job_id = harness .submit(SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: "https://example.invalid/slow".into(), result_path: "slow.bin".into(), credential_id: None, })) .await; let task = tokio::spawn(async move { runtime.run_once().await.unwrap() }); executor.started.notified().await; harness .coordination .drop_job_state(&[job_id.as_str()]) .await .unwrap(); assert_eq!(task.await.unwrap(), WorkerRunOutcome::AuthorityLost); assert!(executor.stale_report_failed.load(Ordering::Acquire) > 0); } #[tokio::test] async fn cancellation_stops_the_attempt_and_credential_outage_is_retryable() { let Some(harness) = Harness::new("cancel-outage").await else { return; }; let blocking = Arc::new(ProtocolExecutor::blocking(harness.pool.clone())); let runtime = harness.runtime(blocking.clone()); let job_id = harness .submit(SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: "https://example.invalid/cancel".into(), result_path: "cancel.bin".into(), credential_id: None, })) .await; let task = tokio::spawn(async move { runtime.run_once().await.unwrap() }); blocking.started.notified().await; harness.attempts.request_cancel(&job_id).await.unwrap(); harness .coordination .publish_cancel(job_id.as_str()) .await .unwrap(); assert_eq!(task.await.unwrap(), WorkerRunOutcome::Cancelled); let fixture = SourceFixture::start().await; let target = TargetStoreConfig::from_env().unwrap(); let (credential_id, resolver) = object_credential(&harness, true).await; let runtime = harness.runtime(production_executor( &harness, &fixture, resolver, target, "source-store", )); let job_id = harness .submit(SourceSubmissionDto::ObjectStore( ObjectStoreSourceSubmissionDto { store: "source-store".into(), bucket: std::env::var("REMORA_TARGET_BUCKET").unwrap(), key: "credential-outage.bin".into(), version_id: None, result_path: "credential.bin".into(), credential_id: Some(credential_id), }, )) .await; assert_eq!( runtime.run_once().await.unwrap(), WorkerRunOutcome::Failed(JobPhase::RetryWait) ); let phase: String = sqlx::query_scalar("SELECT phase FROM jobs WHERE job_id = $1") .bind(job_id.as_str()) .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(phase, "retry_wait"); } #[tokio::test] async fn crashed_process_is_reaped_and_restarted_with_fresh_authority() { let Some(harness) = Harness::new("restart").await else { return; }; let crashed = Arc::new(ProtocolExecutor::crash_blocking(harness.pool.clone())); let first = harness.runtime(crashed.clone()); let first_incarnation = first.incarnation().clone(); let job_id = harness .submit(SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: "https://example.invalid/restart".into(), result_path: "restart.bin".into(), credential_id: None, })) .await; let task = tokio::spawn(async move { first.run_once().await }); crashed.started.notified().await; task.abort(); assert!(task.await.unwrap_err().is_cancelled()); harness .coordination .drop_job_state(&[job_id.as_str()]) .await .unwrap(); let recovery = RecoveryConfig { retry_delay: Duration::ZERO, ..RecoveryConfig::default() }; assert_eq!( harness .attempts .reconcile_once(&recovery) .await .unwrap() .attempts_reaped, 1 ); assert_eq!( harness .attempts .reconcile_once(&recovery) .await .unwrap() .retries_scheduled, 1 ); let restarted = harness.runtime(Arc::new(ProtocolExecutor::success(harness.pool.clone()))); assert_ne!(first_incarnation, *restarted.incarnation()); assert_eq!( restarted.run_once().await.unwrap(), WorkerRunOutcome::Succeeded ); let attempts: Vec<(i64, String)> = sqlx::query_as( "SELECT fence, worker_incarnation FROM attempts WHERE job_id = $1 ORDER BY fence", ) .bind(job_id.as_str()) .fetch_all(&harness.pool) .await .unwrap(); assert_eq!(attempts.len(), 2); assert_eq!(attempts[0].0, 1); assert_eq!(attempts[1].0, 2); assert_ne!(attempts[0].1, attempts[1].1); } #[tokio::test] async fn local_limit_bounds_concurrent_attempt_tasks() { let Some(harness) = Harness::new("local-limit").await else { return; }; let executor = Arc::new(ConcurrencyExecutor::default()); for suffix in ["one", "two", "three"] { harness .submit(SourceSubmissionDto::Http(HttpSourceSubmissionDto { url: format!("https://example.invalid/{suffix}"), result_path: format!("{suffix}.bin"), credential_id: None, })) .await; } let shutdown = CancelToken::new(); let runtime = harness.runtime(executor.clone()); let task = tokio::spawn({ let shutdown = shutdown.clone(); async move { runtime.run(shutdown).await } }); tokio::time::timeout(Duration::from_secs(5), async { while executor.active.load(Ordering::Acquire) < 2 { tokio::task::yield_now().await; } }) .await .unwrap(); tokio::time::sleep(Duration::from_millis(100)).await; assert_eq!(executor.active.load(Ordering::Acquire), 2); let executing: i64 = sqlx::query_scalar("SELECT count(*) FROM attempts WHERE state = 'executing'") .fetch_one(&harness.pool) .await .unwrap(); assert_eq!(executing, 2); shutdown.cancel(); task.await.unwrap().unwrap(); } #[derive(Clone, Copy)] enum ExecutorMode { Success, Blocking, CrashBlocking, } #[derive(Clone)] struct ProtocolExecutor { pool: PgPool, mode: ExecutorMode, started: Arc, stale_report_failed: Arc, } impl ProtocolExecutor { fn success(pool: PgPool) -> Self { Self::new(pool, ExecutorMode::Success) } fn blocking(pool: PgPool) -> Self { Self::new(pool, ExecutorMode::Blocking) } fn crash_blocking(pool: PgPool) -> Self { Self::new(pool, ExecutorMode::CrashBlocking) } fn new(pool: PgPool, mode: ExecutorMode) -> Self { Self { pool, mode, started: Arc::new(tokio::sync::Notify::new()), stale_report_failed: Arc::new(AtomicUsize::new(0)), } } async fn run( &self, context: AttemptContext, envelope: remora_contracts::ExecutionEnvelopeDto, ) -> AttemptExecution { if matches!(self.mode, ExecutorMode::CrashBlocking) { self.started.notify_one(); std::future::pending().await } let descriptors = DescriptorStore::new(self.pool.clone()); let resolved = descriptors .store_resolved( &envelope.attempt_id, &serde_json::json!({ "kind": source_kind(&envelope.source) }), Some(1), ) .await .unwrap(); context.pin_resolved_source(resolved.clone()).await.unwrap(); let checkpoint = descriptors .store_checkpoint( &envelope.attempt_id, &serde_json::json!({ "resolved_source_id": resolved.id, "validated_bytes": 1, "validated_members": 1 }), Some(0), ) .await .unwrap(); context .persist_checkpoint(checkpoint, resolved.id, safe(1), safe(1), None) .await .unwrap(); context .report_progress(ProgressValueDto { completed_bytes: safe(64), total_bytes: Some(safe(64)), completed_members: safe(1), total_members: Some(safe(1)), }) .await .unwrap(); if matches!(self.mode, ExecutorMode::Blocking) { self.started.notify_one(); context.cancellation().cancelled().await; if context .report_progress(ProgressValueDto { completed_bytes: safe(65), total_bytes: Some(safe(65)), completed_members: safe(1), total_members: Some(safe(1)), }) .await .is_err() { self.stale_report_failed.fetch_add(1, Ordering::Release); } return AttemptExecution::Cancelled; } AttemptExecution::Succeeded(seal_result(&self.pool, &envelope).await) } } #[derive(Default)] struct ConcurrencyExecutor { active: AtomicUsize, } impl AttemptExecutor for ConcurrencyExecutor { fn execute( &self, _context: AttemptContext, _envelope: remora_contracts::ExecutionEnvelopeDto, ) -> Pin + Send>> { self.active.fetch_add(1, Ordering::AcqRel); Box::pin(std::future::pending()) } } impl AttemptExecutor for ProtocolExecutor { fn execute( &self, context: AttemptContext, envelope: remora_contracts::ExecutionEnvelopeDto, ) -> Pin + Send>> { let executor = self.clone(); Box::pin(async move { executor.run(context, envelope).await }) } } async fn seal_result( pool: &PgPool, envelope: &remora_contracts::ExecutionEnvelopeDto, ) -> ResultDescriptorDto { let manifest_id = unique_id("manifest"); let checksum = format!("sha256:{}", "11".repeat(32)); let key = attempt_manifest_key_in(&envelope.target.prefix, &envelope.attempt_id, &manifest_id); sqlx::query( "INSERT INTO result_inventories ( attempt_id, state, manifest_schema_version, manifest_id, manifest_store, manifest_bucket, manifest_key, manifest_version_id, manifest_sha256, manifest_size, member_count, total_bytes, staging_origin_attempt_id, target_prefix ) VALUES ($1, 'sealed', 1, $2, $3, $4, $5, 'version-1', $6, 128, 1, 64, $1, $7)", ) .bind(envelope.attempt_id.as_str()) .bind(manifest_id.as_str()) .bind(&envelope.target.store) .bind(&envelope.target.bucket) .bind(&key) .bind(&checksum) .bind(&envelope.target.prefix) .execute(pool) .await .unwrap(); ResultDescriptorDto { kind: ResultKindDto::Manifest, manifest_id, schema_version: positive(1), manifest: ObjectIdentityDto { store: envelope.target.store.clone(), bucket: envelope.target.bucket.clone(), key, version_id: Some("version-1".into()), checksum, size: safe(128), }, member_count: positive(1), total_bytes: safe(64), } } fn source_kind(source: &SourceProjectionDto) -> &'static str { match source { SourceProjectionDto::Http(_) => "http", SourceProjectionDto::ObjectStore(_) => "object_store", SourceProjectionDto::HuggingFace(_) => "hugging_face", } } const SOURCE_BODY: &[u8] = b"source-body"; const MULTIPART_BOUNDARY: usize = 5 * 1024 * 1024; const LARGE_SOURCE_SIZE: usize = MULTIPART_BOUNDARY * 2 + 123; const HF_BODY: &[u8] = b"hf-body"; const HF_COMMIT: &str = "0123456789abcdef0123456789abcdef01234567"; struct SourceFixture { base_url: String, port: u16, root_der: Vec, server: actix_web::dev::ServerHandle, range_requests: Arc, } impl SourceFixture { async fn start() -> Self { let mut ca_params = CertificateParams::new(Vec::new()).unwrap(); ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); ca_params.key_usages = vec![ KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign, ]; let ca_key = KeyPair::generate().unwrap(); let ca = ca_params.self_signed(&ca_key).unwrap(); let issuer = Issuer::new(ca_params, ca_key); let server_key = KeyPair::generate().unwrap(); let mut server_params = CertificateParams::new(vec!["127.0.0.1".into()]).unwrap(); server_params.key_usages = vec![KeyUsagePurpose::DigitalSignature]; server_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; let server = server_params.signed_by(&server_key, &issuer).unwrap(); let root_der = ca.der().as_ref().to_vec(); let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(server_key.serialize_der())); let server_config = ServerConfig::builder() .with_no_client_auth() .with_single_cert(vec![server.der().clone()], key) .unwrap(); let listener = TcpListener::bind("127.0.0.1:443").unwrap(); let address = listener.local_addr().unwrap(); let range_requests = Arc::new(AtomicUsize::new(0)); let fixture = web::Data::new(SourceFixtureData { large_body: Arc::new(vec![0x5a; LARGE_SOURCE_SIZE]), range_requests: range_requests.clone(), }); let server = HttpServer::new(move || { App::new() .app_data(fixture.clone()) .default_service(web::to(source_response)) }) .listen_rustls_0_23(listener, server_config) .unwrap() .run(); let handle = server.handle(); tokio::spawn(server); Self { base_url: "https://127.0.0.1".into(), port: address.port(), root_der, server: handle, range_requests, } } } impl Drop for SourceFixture { fn drop(&mut self) { let server = self.server.clone(); tokio::spawn(async move { server.stop(true).await }); } } struct SourceFixtureData { large_body: Arc>, range_requests: Arc, } async fn source_response( request: HttpRequest, fixture: web::Data, ) -> HttpResponse { let path = request.path(); if path == "/http.bin" { return HttpResponse::Ok() .insert_header((header::ETAG, "\"source-v1\"")) .body(SOURCE_BODY); } if path == "/large.bin" { if let Some(range) = request .headers() .get(header::RANGE) .and_then(|value| value.to_str().ok()) { let offset = range .strip_prefix("bytes=") .and_then(|value| value.strip_suffix('-')) .and_then(|value| value.parse::().ok()) .filter(|offset| *offset < fixture.large_body.len()); let valid_if_range = request .headers() .get(header::IF_MATCH) .and_then(|value| value.to_str().ok()) == Some("\"large-v1\""); let Some(offset) = offset.filter(|_| valid_if_range) else { return HttpResponse::PreconditionFailed().finish(); }; fixture.range_requests.fetch_add(1, Ordering::AcqRel); return HttpResponse::PartialContent() .insert_header((header::ETAG, "\"large-v1\"")) .insert_header(( header::CONTENT_RANGE, format!( "bytes {offset}-{}/{}", fixture.large_body.len() - 1, fixture.large_body.len() ), )) .body(fixture.large_body[offset..].to_vec()); } let body = fixture.large_body.clone(); let chunks = stream::unfold(0_usize, move |offset| { let body = body.clone(); async move { if offset >= body.len() { return None; } if offset == MULTIPART_BOUNDARY { tokio::time::sleep(Duration::from_secs(2)).await; } let end = (offset + 64 * 1024).min(body.len()); Some(( Ok::<_, std::io::Error>(bytes::Bytes::copy_from_slice(&body[offset..end])), end, )) } }); return HttpResponse::Ok() .insert_header((header::ETAG, "\"large-v1\"")) .insert_header((header::CONTENT_LENGTH, fixture.large_body.len())) .streaming(chunks); } if path.ends_with(&format!("/revision/{HF_COMMIT}")) { return HttpResponse::Ok().json(serde_json::json!({ "id": "owner/model", "sha": HF_COMMIT })); } if path.contains(&format!("/tree/{HF_COMMIT}")) { return HttpResponse::Ok().json(serde_json::json!([ { "type": "file", "oid": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "size": 0, "path": "empty.bin", "lfs": null }, { "type": "file", "oid": "af0f6ad1a70708b53ec3774c084bee9ad41f1984", "size": HF_BODY.len(), "path": "model.bin", "lfs": null } ])); } if path.ends_with(&format!("/resolve/{HF_COMMIT}/empty.bin")) { return HttpResponse::Ok().body(""); } if path.ends_with(&format!("/resolve/{HF_COMMIT}/model.bin")) { return HttpResponse::Ok().body(HF_BODY); } HttpResponse::NotFound().finish() } async fn object_credential( harness: &Harness, resolver_outage: bool, ) -> (OpaqueId, GrantBoundResolver) { let vault_config = VaultConfig::from_env().unwrap(); let vault = VaultClient::new(vault_config.clone()).unwrap(); let registry = CredentialRegistry::new(harness.pool.clone(), vault.clone()); let credential = registry .create( &harness.owner, CreateCredential { label: unique_id("label").to_string(), material: SecretMaterial::ObjectStore { access_key_id: std::env::var("REMORA_TARGET_ACCESS_KEY").unwrap(), secret_access_key: std::env::var("REMORA_TARGET_SECRET_KEY").unwrap(), session_token: None, }, }, ) .await .unwrap(); let resolver_vault = if resolver_outage { VaultClient::new(VaultConfig { address: "http://127.0.0.1:9".into(), timeout: Duration::from_millis(100), ..vault_config }) .unwrap() } else { vault }; ( credential.id, GrantBoundResolver::new(registry, resolver_vault), ) } async fn object_credentialless_resolver(harness: &Harness) -> GrantBoundResolver { let vault = VaultClient::new(VaultConfig::from_env().unwrap()).unwrap(); GrantBoundResolver::new( CredentialRegistry::new(harness.pool.clone(), vault.clone()), vault, ) } fn production_executor( harness: &Harness, fixture: &SourceFixture, resolver: GrantBoundResolver, target: TargetStoreConfig, source_store: &str, ) -> Arc { let object_sources = BTreeMap::from([( source_store.to_owned(), ObjectSourceEndpoint { endpoint: target.endpoint.clone(), region: target.region.clone(), }, )]); let outbound = OutboundPolicyBuilder::new() .allow_scheme_port("https", fixture.port) .allow_non_global("127.0.0.0/8".parse().unwrap()) .allow_non_global("::1/128".parse().unwrap()) .build(); let copy = CopyConfig { progress_interval_bytes: 1, checkpoint_interval_bytes: 1, ..CopyConfig::default() }; Arc::new( AdapterExecutor::new( harness.pool.clone(), resolver, target, object_sources, outbound, RetryTiming::default_bounds(), copy, &fixture.base_url, ) .unwrap() .with_outbound_root_certificate_der(fixture.root_der.clone()), ) } async fn start_server(state: WorkerApiState) -> (String, actix_web::dev::ServerHandle, Client) { let certificates = certificates(); let client = trusted_client(&certificates); let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let address = listener.local_addr().unwrap(); let server = HttpServer::new(move || { App::new() .app_data(web::Data::new(state.clone())) .configure(configure_worker_api) }) .on_connect(authenticate_rustls_worker) .listen_rustls_0_23(listener, certificates.server_config) .unwrap() .run(); let handle = server.handle(); tokio::spawn(server); ( format!("https://localhost:{}", address.port()), handle, client, ) } fn trusted_client(certificates: &Certificates) -> Client { let root = ClientCertificate::from_der(certificates.ca.der()).unwrap(); let mut client_pem = certificates.client.pem(); client_pem.push_str(&certificates.client_key.serialize_pem()); Client::builder() .add_root_certificate(root) .identity(Identity::from_pem(client_pem.as_bytes()).unwrap()) .build() .unwrap() } struct Certificates { ca: Certificate, client: Certificate, client_key: KeyPair, server_config: ServerConfig, } fn certificates() -> Certificates { let _ = rustls::crypto::ring::default_provider().install_default(); let mut ca_params = CertificateParams::new(Vec::new()).unwrap(); ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); ca_params.key_usages = vec![ KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign, ]; let ca_key = KeyPair::generate().unwrap(); let ca = ca_params.self_signed(&ca_key).unwrap(); let issuer = Issuer::new(ca_params, ca_key); let server_key = KeyPair::generate().unwrap(); let mut server_params = CertificateParams::new(vec!["localhost".into()]).unwrap(); server_params.key_usages = vec![KeyUsagePurpose::DigitalSignature]; server_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; let server = server_params.signed_by(&server_key, &issuer).unwrap(); let client_key = KeyPair::generate().unwrap(); let mut client_params = CertificateParams::new(Vec::new()).unwrap(); client_params.key_usages = vec![KeyUsagePurpose::DigitalSignature]; client_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth]; let client = client_params.signed_by(&client_key, &issuer).unwrap(); let mut roots = RootCertStore::empty(); roots.add(ca.der().clone()).unwrap(); let verifier = WebPkiClientVerifier::builder(Arc::new(roots)) .build() .unwrap(); let server_key_der = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(server_key.serialize_der())); let server_config = ServerConfig::builder() .with_client_cert_verifier(verifier) .with_single_cert(vec![server.der().clone()], server_key_der) .unwrap(); Certificates { ca, client, client_key, server_config, } } fn required_env(name: &str) -> Option { match std::env::var(name) { Ok(value) if !value.is_empty() => Some(value), _ if std::env::var_os("REMORA_WORKER_REQUIRE").is_some() => { panic!("{name} is required") } _ => None, } } fn coordination_namespace() -> String { std::env::var("REMORA_COORDINATION_NAMESPACE").unwrap_or_else(|_| "remora:test:".into()) } fn nonce() -> u128 { use std::sync::atomic::{AtomicU64, Ordering}; static COUNTER: AtomicU64 = AtomicU64::new(0); (u128::from(std::process::id()) << 64) | u128::from(COUNTER.fetch_add(1, Ordering::Relaxed)) } fn unique_id(prefix: &str) -> OpaqueId { OpaqueId::parse(format!("{prefix}{:032x}", nonce())).unwrap() } fn positive(value: u64) -> PositiveIntegerDto { PositiveIntegerDto::new(value).unwrap() } fn safe(value: u64) -> SafeIntegerDto { SafeIntegerDto::new(value).unwrap() } fn resolved_descriptor(value: &ResolvedSourceDescriptorRefDto) -> DurableDescriptor { DurableDescriptor { id: value.id.clone(), schema_version: u32::try_from(value.schema_version.get()).unwrap(), byte_length: value.byte_length.get(), item_count: value.item_count.map(SafeIntegerDto::get), checksum: value.checksum.clone(), } } fn checkpoint_descriptor(value: &CheckpointDescriptorRefDto) -> DurableDescriptor { DurableDescriptor { id: value.id.clone(), schema_version: u32::try_from(value.schema_version.get()).unwrap(), byte_length: value.byte_length.get(), item_count: value.item_count.map(SafeIntegerDto::get), checksum: value.checksum.clone(), } } fn digest_text(value: &str) -> String { Sha256::digest(value.as_bytes()) .iter() .fold(String::from("sha256:"), |mut output, byte| { use std::fmt::Write as _; write!(output, "{byte:02x}").unwrap(); output }) }