mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-01 21:13:09 +00:00
allow concurrency in service actor (#2592)
This commit is contained in:
@@ -4,19 +4,27 @@ use models::{ActionId, ProcedureName};
|
||||
|
||||
use crate::action::ActionResult;
|
||||
use crate::prelude::*;
|
||||
use crate::service::config::GetConfig;
|
||||
use crate::service::dependencies::DependencyConfig;
|
||||
use crate::service::{Service, ServiceActor};
|
||||
use crate::util::actor::{BackgroundJobs, Handler};
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::actor::{ConflictBuilder, Handler};
|
||||
|
||||
struct Action {
|
||||
pub(super) struct Action {
|
||||
id: ActionId,
|
||||
input: Value,
|
||||
}
|
||||
impl Handler<Action> for ServiceActor {
|
||||
type Response = Result<ActionResult, Error>;
|
||||
fn conflicts_with(_: &Action) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::everything()
|
||||
.except::<GetConfig>()
|
||||
.except::<DependencyConfig>()
|
||||
}
|
||||
async fn handle(
|
||||
&mut self,
|
||||
Action { id, input }: Action,
|
||||
_: &mut BackgroundJobs,
|
||||
_: &BackgroundJobQueue,
|
||||
) -> Self::Response {
|
||||
let container = &self.0.persistent_container;
|
||||
container
|
||||
|
||||
@@ -3,19 +3,24 @@ use std::time::Duration;
|
||||
use models::ProcedureName;
|
||||
|
||||
use crate::config::action::ConfigRes;
|
||||
use crate::config::{action::SetResult, ConfigureContext};
|
||||
use crate::config::ConfigureContext;
|
||||
use crate::prelude::*;
|
||||
use crate::service::dependencies::DependencyConfig;
|
||||
use crate::service::{Service, ServiceActor};
|
||||
use crate::util::actor::{BackgroundJobs, Handler};
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::actor::{ConflictBuilder, Handler};
|
||||
use crate::util::serde::NoOutput;
|
||||
|
||||
struct Configure(ConfigureContext);
|
||||
pub(super) struct Configure(ConfigureContext);
|
||||
impl Handler<Configure> for ServiceActor {
|
||||
type Response = Result<(), Error>;
|
||||
fn conflicts_with(_: &Configure) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::everything().except::<DependencyConfig>()
|
||||
}
|
||||
async fn handle(
|
||||
&mut self,
|
||||
Configure(ConfigureContext { timeout, config }): Configure,
|
||||
_: &mut BackgroundJobs,
|
||||
_: &BackgroundJobQueue,
|
||||
) -> Self::Response {
|
||||
let container = &self.0.persistent_container;
|
||||
let package_id = &self.0.id;
|
||||
@@ -41,10 +46,13 @@ impl Handler<Configure> for ServiceActor {
|
||||
}
|
||||
}
|
||||
|
||||
struct GetConfig;
|
||||
pub(super) struct GetConfig;
|
||||
impl Handler<GetConfig> for ServiceActor {
|
||||
type Response = Result<ConfigRes, Error>;
|
||||
async fn handle(&mut self, _: GetConfig, _: &mut BackgroundJobs) -> Self::Response {
|
||||
fn conflicts_with(_: &GetConfig) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::nothing().except::<Configure>()
|
||||
}
|
||||
async fn handle(&mut self, _: GetConfig, _: &BackgroundJobQueue) -> Self::Response {
|
||||
let container = &self.0.persistent_container;
|
||||
container
|
||||
.execute::<ConfigRes>(
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
use crate::prelude::*;
|
||||
use crate::service::config::GetConfig;
|
||||
use crate::service::dependencies::DependencyConfig;
|
||||
use crate::service::start_stop::StartStop;
|
||||
use crate::service::transition::TransitionKind;
|
||||
use crate::service::{Service, ServiceActor};
|
||||
use crate::util::actor::{BackgroundJobs, Handler};
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::actor::{ConflictBuilder, Handler};
|
||||
|
||||
struct Start;
|
||||
pub(super) struct Start;
|
||||
impl Handler<Start> for ServiceActor {
|
||||
type Response = ();
|
||||
async fn handle(&mut self, _: Start, _: &mut BackgroundJobs) -> Self::Response {
|
||||
fn conflicts_with(_: &Start) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::everything()
|
||||
.except::<GetConfig>()
|
||||
.except::<DependencyConfig>()
|
||||
}
|
||||
async fn handle(&mut self, _: Start, _: &BackgroundJobQueue) -> Self::Response {
|
||||
self.0.persistent_container.state.send_modify(|x| {
|
||||
x.desired_state = StartStop::Start;
|
||||
});
|
||||
@@ -23,7 +31,12 @@ impl Service {
|
||||
struct Stop;
|
||||
impl Handler<Stop> for ServiceActor {
|
||||
type Response = ();
|
||||
async fn handle(&mut self, _: Stop, _: &mut BackgroundJobs) -> Self::Response {
|
||||
fn conflicts_with(_: &Stop) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::everything()
|
||||
.except::<GetConfig>()
|
||||
.except::<DependencyConfig>()
|
||||
}
|
||||
async fn handle(&mut self, _: Stop, _: &BackgroundJobQueue) -> Self::Response {
|
||||
let mut transition_state = None;
|
||||
self.0.persistent_container.state.send_modify(|x| {
|
||||
x.desired_state = StartStop::Stop;
|
||||
|
||||
@@ -5,22 +5,26 @@ use models::{PackageId, ProcedureName};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::service::{Service, ServiceActor};
|
||||
use crate::util::actor::{BackgroundJobs, Handler};
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::actor::{ConflictBuilder, Handler};
|
||||
use crate::Config;
|
||||
|
||||
struct DependencyConfig {
|
||||
pub(super) struct DependencyConfig {
|
||||
dependency_id: PackageId,
|
||||
remote_config: Option<Config>,
|
||||
}
|
||||
impl Handler<DependencyConfig> for ServiceActor {
|
||||
type Response = Result<Option<Config>, Error>;
|
||||
fn conflicts_with(_: &DependencyConfig) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::nothing()
|
||||
}
|
||||
async fn handle(
|
||||
&mut self,
|
||||
DependencyConfig {
|
||||
dependency_id,
|
||||
remote_config,
|
||||
}: DependencyConfig,
|
||||
_: &mut BackgroundJobs,
|
||||
_: &BackgroundJobQueue,
|
||||
) -> Self::Response {
|
||||
let container = &self.0.persistent_container;
|
||||
container
|
||||
|
||||
@@ -13,7 +13,6 @@ use start_stop::StartStop;
|
||||
use tokio::sync::Notify;
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::config::action::ConfigRes;
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::core::rpc_continuations::RequestGuid;
|
||||
use crate::db::model::package::{
|
||||
@@ -28,7 +27,9 @@ use crate::service::service_map::InstallProgressHandles;
|
||||
use crate::service::transition::TransitionKind;
|
||||
use crate::status::health_check::HealthCheckResult;
|
||||
use crate::status::MainStatus;
|
||||
use crate::util::actor::{Actor, BackgroundJobs, SimpleActor};
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::actor::concurrent::ConcurrentActor;
|
||||
use crate::util::actor::Actor;
|
||||
use crate::util::serde::Pem;
|
||||
use crate::volume::data_dir;
|
||||
|
||||
@@ -66,7 +67,7 @@ pub enum LoadDisposition {
|
||||
}
|
||||
|
||||
pub struct Service {
|
||||
actor: SimpleActor<ServiceActor>,
|
||||
actor: ConcurrentActor<ServiceActor>,
|
||||
seed: Arc<ServiceActorSeed>,
|
||||
}
|
||||
impl Service {
|
||||
@@ -90,7 +91,7 @@ impl Service {
|
||||
.init(Arc::downgrade(&seed))
|
||||
.await?;
|
||||
Ok(Self {
|
||||
actor: SimpleActor::new(ServiceActor(seed.clone())),
|
||||
actor: ConcurrentActor::new(ServiceActor(seed.clone())),
|
||||
seed,
|
||||
})
|
||||
}
|
||||
@@ -391,10 +392,11 @@ impl ServiceActorSeed {
|
||||
});
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
struct ServiceActor(Arc<ServiceActorSeed>);
|
||||
|
||||
impl Actor for ServiceActor {
|
||||
fn init(&mut self, jobs: &mut BackgroundJobs) {
|
||||
fn init(&mut self, jobs: &BackgroundJobQueue) {
|
||||
let seed = self.0.clone();
|
||||
jobs.add_job(async move {
|
||||
let id = seed.id.clone();
|
||||
|
||||
@@ -11,7 +11,7 @@ use clap::Parser;
|
||||
use emver::VersionRange;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::{json, InternedString};
|
||||
use models::{ActionId, HealthCheckId, HostId, ImageId, PackageId, VolumeId};
|
||||
use models::{ActionId, DataUrl, HealthCheckId, HostId, ImageId, PackageId, VolumeId};
|
||||
use patch_db::json_ptr::JsonPointer;
|
||||
use rpc_toolkit::{from_fn, from_fn_async, AnyContext, Context, Empty, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -28,7 +28,9 @@ use crate::disk::mount::filesystem::overlayfs::OverlayGuard;
|
||||
use crate::net::host::binding::BindOptions;
|
||||
use crate::net::host::HostKind;
|
||||
use crate::prelude::*;
|
||||
use crate::s9pk::merkle_archive::source::http::{HttpReader, HttpSource};
|
||||
use crate::s9pk::rpc::SKIP_ENV;
|
||||
use crate::s9pk::S9pk;
|
||||
use crate::service::cli::ContainerCliContext;
|
||||
use crate::service::ServiceActorSeed;
|
||||
use crate::status::health_check::HealthCheckResult;
|
||||
@@ -1145,11 +1147,36 @@ async fn set_dependencies(
|
||||
version_spec,
|
||||
),
|
||||
};
|
||||
let icon = todo!();
|
||||
let title = todo!();
|
||||
let (icon, title) = match async {
|
||||
let remote_s9pk = S9pk::deserialize(
|
||||
&HttpSource::new(
|
||||
ctx.ctx.client.clone(),
|
||||
registry_url
|
||||
.join(&format!("package/v2/{}.s9pk?spec={}", dep_id, version_spec))?,
|
||||
)
|
||||
.await?,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let icon = remote_s9pk.icon_data_url().await?;
|
||||
|
||||
Ok::<_, Error>((icon, remote_s9pk.as_manifest().title.clone()))
|
||||
}
|
||||
.await
|
||||
{
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
tracing::error!("Error fetching remote s9pk: {e}");
|
||||
tracing::debug!("{e:?}");
|
||||
(
|
||||
DataUrl::from_slice("image/png", include_bytes!("../install/package-icon.png")),
|
||||
dep_id.to_string(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let config_satisfied = if let Some(dep_service) = &*ctx.ctx.services.get(&dep_id).await {
|
||||
service
|
||||
.dependency_config(dep_id, dep_service.get_config().await?.config)
|
||||
.dependency_config(dep_id.clone(), dep_service.get_config().await?.config)
|
||||
.await?
|
||||
.is_none()
|
||||
} else {
|
||||
@@ -1158,7 +1185,7 @@ async fn set_dependencies(
|
||||
deps.insert(
|
||||
dep_id,
|
||||
CurrentDependencyInfo {
|
||||
kind: CurrentDependencyKind::Exists,
|
||||
kind,
|
||||
registry_url,
|
||||
version_spec,
|
||||
icon,
|
||||
|
||||
@@ -5,7 +5,7 @@ use tokio::sync::watch;
|
||||
|
||||
use super::persistent_container::ServiceState;
|
||||
use crate::service::start_stop::StartStop;
|
||||
use crate::util::actor::BackgroundJobs;
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::future::{CancellationHandle, RemoteCancellable};
|
||||
|
||||
pub mod backup;
|
||||
@@ -41,7 +41,7 @@ impl TransitionState {
|
||||
fn new(
|
||||
task: impl Future<Output = ()> + Send + 'static,
|
||||
kind: TransitionKind,
|
||||
jobs: &mut BackgroundJobs,
|
||||
jobs: &BackgroundJobQueue,
|
||||
) -> Self {
|
||||
let task = RemoteCancellable::new(task);
|
||||
let cancel_handle = task.cancellation_handle();
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::FutureExt;
|
||||
|
||||
use super::TempDesiredState;
|
||||
use crate::prelude::*;
|
||||
use crate::service::config::GetConfig;
|
||||
use crate::service::dependencies::DependencyConfig;
|
||||
use crate::service::transition::{TransitionKind, TransitionState};
|
||||
use crate::service::{Service, ServiceActor};
|
||||
use crate::util::actor::{BackgroundJobs, Handler};
|
||||
use crate::util::actor::background::BackgroundJobQueue;
|
||||
use crate::util::actor::{ConflictBuilder, Handler};
|
||||
use crate::util::future::RemoteCancellable;
|
||||
|
||||
struct Restart;
|
||||
pub(super) struct Restart;
|
||||
impl Handler<Restart> for ServiceActor {
|
||||
type Response = ();
|
||||
async fn handle(&mut self, _: Restart, jobs: &mut BackgroundJobs) -> Self::Response {
|
||||
fn conflicts_with(_: &Restart) -> ConflictBuilder<Self> {
|
||||
ConflictBuilder::everything()
|
||||
.except::<GetConfig>()
|
||||
.except::<DependencyConfig>()
|
||||
}
|
||||
async fn handle(&mut self, _: Restart, jobs: &BackgroundJobQueue) -> Self::Response {
|
||||
// So Need a handle to just a single field in the state
|
||||
let temp = TempDesiredState::new(&self.0.persistent_container.state);
|
||||
let mut current = self.0.persistent_container.state.subscribe();
|
||||
|
||||
Reference in New Issue
Block a user