Skip to content

Commit

Permalink
Get things compiling
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Levick <ryan.levick@fermyon.com>
  • Loading branch information
rylev committed Aug 20, 2024
1 parent c578fdd commit 6a67cef
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 121 deletions.
6 changes: 4 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/trigger-http2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use spin_http::{config::HttpTriggerConfig, routes::Router};
use spin_trigger2::Trigger;
use wasmtime_wasi_http::bindings::wasi::http::types::ErrorCode;

use server::HttpServer;
pub use server::HttpServer;

pub use tls::TlsConfig;

Expand Down
218 changes: 145 additions & 73 deletions crates/trigger2/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod launch_metadata;

use std::path::PathBuf;
use std::future::Future;
use std::path::{Path, PathBuf};

use anyhow::{Context, Result};
use clap::{Args, IntoApp, Parser};
Expand All @@ -13,7 +14,7 @@ use spin_runtime_config::ResolvedRuntimeConfig;

use crate::factors::{TriggerFactors, TriggerFactorsRuntimeConfig};
use crate::stdio::{FollowComponents, StdioLoggingExecutorHooks};
use crate::Trigger;
use crate::{Trigger, TriggerApp};
pub use launch_metadata::LaunchMetadata;

pub const APP_LOG_DIR: &str = "APP_LOG_DIR";
Expand Down Expand Up @@ -172,43 +173,154 @@ impl<T: Trigger> FactorsTriggerCommand<T> {
anyhow::bail!("This application requires the following features that are not available in this version of the '{}' trigger: {unmet}", T::TYPE);
}

let mut trigger = T::new(self.trigger_args, &app)?;
let trigger = T::new(self.trigger_args, &app)?;
let mut builder = TriggerAppBuilder::new(trigger, PathBuf::from(working_dir));
let config = builder.engine_config();

let mut core_engine_builder = {
let mut config = spin_core::Config::default();
// Apply --cache / --disable-cache
if !self.disable_cache {
config.enable_cache(&self.cache)?;
}

// Apply --cache / --disable-cache
if !self.disable_cache {
config.enable_cache(&self.cache)?;
}
if self.disable_pooling {
config.disable_pooling();
}

if self.disable_pooling {
config.disable_pooling();
let run_fut = builder
.run(
app,
TriggerAppOptions {
runtime_config_file: self.runtime_config_file.as_deref(),
state_dir: self.state_dir.as_deref(),
initial_key_values: self.key_values,
allow_transient_write: self.allow_transient_write,
follow_components,
log_dir: self.log,
},
)
.await?;

let (abortable, abort_handle) = futures::future::abortable(run_fut);
ctrlc::set_handler(move || abort_handle.abort())?;
match abortable.await {
Ok(Ok(())) => {
tracing::info!("Trigger executor shut down: exiting");
Ok(())
}
Ok(Err(err)) => {
tracing::error!("Trigger executor failed");
Err(err)
}
Err(_aborted) => {
tracing::info!("User requested shutdown: exiting");
Ok(())
}
}
}

fn follow_components(&self) -> FollowComponents {
if self.silence_component_logs {
FollowComponents::None
} else if self.follow_components.is_empty() {
FollowComponents::All
} else {
let followed = self.follow_components.clone().into_iter().collect();
FollowComponents::Named(followed)
}
}
}

const SLOTH_WARNING_DELAY_MILLIS: u64 = 1250;

fn warn_if_wasm_build_slothful() -> sloth::SlothGuard {
#[cfg(debug_assertions)]
let message = "\
This is a debug build - preparing Wasm modules might take a few seconds\n\
If you're experiencing long startup times please switch to the release build";

#[cfg(not(debug_assertions))]
let message = "Preparing Wasm modules is taking a few seconds...";

sloth::warn_if_slothful(SLOTH_WARNING_DELAY_MILLIS, format!("{message}\n"))
}

fn help_heading<T: Trigger>() -> Option<&'static str> {
if T::TYPE == help::HelpArgsOnlyTrigger::TYPE {
Some("TRIGGER OPTIONS")
} else {
let heading = format!("{} TRIGGER OPTIONS", T::TYPE.to_uppercase());
let as_str = Box::new(heading).leak();
Some(as_str)
}
}

/// A builder for a [`TriggerApp`].
pub struct TriggerAppBuilder<T> {
engine_config: spin_core::Config,
working_dir: PathBuf,
pub trigger: T,
}

trigger.update_core_config(&mut config)?;
/// Options for building a [`TriggerApp`].
#[derive(Default)]
pub struct TriggerAppOptions<'a> {
/// Path to the runtime config file.
runtime_config_file: Option<&'a Path>,
/// Path to the state directory.
state_dir: Option<&'a str>,
/// Initial key/value pairs to set in the app's default store.
initial_key_values: Vec<(String, String)>,
/// Whether to allow transient writes to mounted files
allow_transient_write: bool,
/// Which components should have their logs followed.
follow_components: FollowComponents,
/// Log directory for component stdout/stderr.
log_dir: Option<PathBuf>,
}

impl<T: Trigger> TriggerAppBuilder<T> {
pub fn new(trigger: T, working_dir: PathBuf) -> Self {
Self {
engine_config: spin_core::Config::default(),
working_dir,
trigger,
}
}

pub fn engine_config(&mut self) -> &mut spin_core::Config {
&mut self.engine_config
}

spin_core::Engine::builder(&config)?
/// Build a [`TriggerApp`] from the given [`App`] and options.
pub async fn build(
&mut self,
app: App,
options: TriggerAppOptions<'_>,
) -> anyhow::Result<TriggerApp<T>> {
let mut core_engine_builder = {
self.trigger.update_core_config(&mut self.engine_config)?;

spin_core::Engine::builder(&self.engine_config)?
};
trigger.add_to_linker(core_engine_builder.linker())?;
self.trigger.add_to_linker(core_engine_builder.linker())?;

let runtime_config = match &self.runtime_config_file {
let runtime_config = match options.runtime_config_file {
Some(runtime_config_path) => {
ResolvedRuntimeConfig::<TriggerFactorsRuntimeConfig>::from_file(
runtime_config_path,
self.state_dir.as_deref(),
options.state_dir,
)?
}
None => ResolvedRuntimeConfig::default(self.state_dir.as_deref()),
None => ResolvedRuntimeConfig::default(options.state_dir),
};

runtime_config
.set_initial_key_values(&self.key_values)
.set_initial_key_values(&options.initial_key_values)
.await?;

let factors = TriggerFactors::new(
working_dir,
self.allow_transient_write,
self.working_dir.clone(),
options.allow_transient_write,
runtime_config.key_value_resolver,
runtime_config.sqlite_resolver,
);
Expand Down Expand Up @@ -249,8 +361,10 @@ impl<T: Trigger> FactorsTriggerCommand<T> {

let mut executor = FactorsExecutor::new(core_engine_builder, factors)?;

let log_dir = self.log.clone();
executor.add_hooks(StdioLoggingExecutorHooks::new(follow_components, log_dir));
executor.add_hooks(StdioLoggingExecutorHooks::new(
options.follow_components,
options.log_dir,
));
// TODO:
// builder.hooks(SummariseRuntimeConfigHook::new(&self.runtime_config_file));
// builder.hooks(KeyValuePersistenceMessageHook);
Expand All @@ -261,59 +375,17 @@ impl<T: Trigger> FactorsTriggerCommand<T> {
executor.load_app(app, runtime_config.runtime_config, SimpleComponentLoader)?
};

let run_fut = trigger.run(configured_app);

let (abortable, abort_handle) = futures::future::abortable(run_fut);
ctrlc::set_handler(move || abort_handle.abort())?;
match abortable.await {
Ok(Ok(())) => {
tracing::info!("Trigger executor shut down: exiting");
Ok(())
}
Ok(Err(err)) => {
tracing::error!("Trigger executor failed");
Err(err)
}
Err(_aborted) => {
tracing::info!("User requested shutdown: exiting");
Ok(())
}
}
}

fn follow_components(&self) -> FollowComponents {
if self.silence_component_logs {
FollowComponents::None
} else if self.follow_components.is_empty() {
FollowComponents::All
} else {
let followed = self.follow_components.clone().into_iter().collect();
FollowComponents::Named(followed)
}
Ok(configured_app)
}
}

const SLOTH_WARNING_DELAY_MILLIS: u64 = 1250;

fn warn_if_wasm_build_slothful() -> sloth::SlothGuard {
#[cfg(debug_assertions)]
let message = "\
This is a debug build - preparing Wasm modules might take a few seconds\n\
If you're experiencing long startup times please switch to the release build";

#[cfg(not(debug_assertions))]
let message = "Preparing Wasm modules is taking a few seconds...";

sloth::warn_if_slothful(SLOTH_WARNING_DELAY_MILLIS, format!("{message}\n"))
}

fn help_heading<T: Trigger>() -> Option<&'static str> {
if T::TYPE == help::HelpArgsOnlyTrigger::TYPE {
Some("TRIGGER OPTIONS")
} else {
let heading = format!("{} TRIGGER OPTIONS", T::TYPE.to_uppercase());
let as_str = Box::new(heading).leak();
Some(as_str)
/// Run the [`TriggerApp`] with the given [`App`] and options.
pub async fn run(
mut self,
app: App,
options: TriggerAppOptions<'_>,
) -> anyhow::Result<impl Future<Output = anyhow::Result<()>>> {
let configured_app = self.build(app, options).await?;
Ok(self.trigger.run(configured_app))
}
}

Expand Down
9 changes: 2 additions & 7 deletions crates/trigger2/src/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ use tokio::io::AsyncWrite;
use crate::factors::TriggerFactors;

/// Which components should have their logs followed on stdout/stderr.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub enum FollowComponents {
#[default]
/// No components should have their logs followed.
None,
/// Only the specified components should have their logs followed.
Expand All @@ -33,12 +34,6 @@ impl FollowComponents {
}
}

impl Default for FollowComponents {
fn default() -> Self {
Self::None
}
}

/// Implements TriggerHooks, writing logs to a log file and (optionally) stderr
pub struct StdioLoggingExecutorHooks {
follow_components: FollowComponents,
Expand Down
9 changes: 6 additions & 3 deletions tests/conformance-tests/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use anyhow::Context as _;
use test_environment::http::Request;
use testing_framework::runtimes::spin_cli::{SpinCli, SpinConfig};

/// Run a single conformance test against the supplied spin binary.
Expand Down Expand Up @@ -56,9 +57,11 @@ pub fn run_test(
let conformance_tests::config::Invocation::Http(mut invocation) = invocation;
invocation.request.substitute_from_env(&mut env)?;
let spin = env.runtime_mut();
let actual = invocation
.request
.send(|request| spin.make_http_request(request))?;
let actual = invocation.request.send(|request| {
let request =
Request::full(request.method, request.path, request.headers, request.body);
spin.make_http_request(request)
})?;

conformance_tests::assertions::assert_response(&invocation.response, &actual)
.with_context(|| {
Expand Down
6 changes: 4 additions & 2 deletions tests/testing-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ regex = "1.10.2"
reqwest = { workspace = true }
temp-dir = "0.1.11"
test-environment = { workspace = true }
spin-trigger-http = { path = "../../crates/trigger-http" }
spin-factors-executor = { path = "../../crates/factors-executor" }
spin-app = { path = "../../crates/app" }
spin-trigger-http2 = { path = "../../crates/trigger-http2" }
spin-http = { path = "../../crates/http" }
spin-trigger = { path = "../../crates/trigger" }
spin-trigger2 = { path = "../../crates/trigger2" }
spin-loader = { path = "../../crates/loader" }
toml = "0.8.6"
tokio = "1.23"
Expand Down
Loading

0 comments on commit 6a67cef

Please sign in to comment.