Skip to content

Commit 7c4b268

Browse files
committed
Properly handle state_dir
Signed-off-by: Ryan Levick <[email protected]>
1 parent 8050ec9 commit 7c4b268

File tree

4 files changed

+63
-26
lines changed

4 files changed

+63
-26
lines changed

crates/factor-llm/src/spin.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,25 @@ mod local {
3838

3939
/// The default engine creator for the LLM factor when used in the Spin CLI.
4040
pub fn default_engine_creator(
41-
state_dir: PathBuf,
41+
state_dir: Option<PathBuf>,
4242
use_gpu: bool,
43-
) -> impl LlmEngineCreator + 'static {
43+
) -> anyhow::Result<impl LlmEngineCreator + 'static> {
4444
#[cfg(feature = "llm")]
45-
let engine = spin_llm_local::LocalLlmEngine::new(state_dir.join("ai-models"), use_gpu);
45+
let engine = {
46+
use anyhow::Context as _;
47+
let models_dir_parent = match state_dir {
48+
Some(ref dir) => dir.clone(),
49+
None => std::env::current_dir().context("failed to get current working directory")?,
50+
};
51+
spin_llm_local::LocalLlmEngine::new(models_dir_parent.join("ai-models"), use_gpu)
52+
};
4653
#[cfg(not(feature = "llm"))]
4754
let engine = {
4855
let _ = (state_dir, use_gpu);
4956
noop::NoopLlmEngine
5057
};
5158
let engine = Arc::new(Mutex::new(engine)) as Arc<Mutex<dyn LlmEngine>>;
52-
move || engine.clone()
59+
Ok(move || engine.clone())
5360
}
5461

5562
#[async_trait]
@@ -74,7 +81,7 @@ impl LlmEngine for RemoteHttpLlmEngine {
7481

7582
pub fn runtime_config_from_toml(
7683
table: &toml::Table,
77-
state_dir: PathBuf,
84+
state_dir: Option<PathBuf>,
7885
use_gpu: bool,
7986
) -> anyhow::Result<Option<RuntimeConfig>> {
8087
let Some(value) = table.get("llm_compute") else {
@@ -95,7 +102,7 @@ pub enum LlmCompute {
95102
}
96103

97104
impl LlmCompute {
98-
fn into_engine(self, state_dir: PathBuf, use_gpu: bool) -> Arc<Mutex<dyn LlmEngine>> {
105+
fn into_engine(self, state_dir: Option<PathBuf>, use_gpu: bool) -> Arc<Mutex<dyn LlmEngine>> {
99106
match self {
100107
#[cfg(not(feature = "llm"))]
101108
LlmCompute::Spin => {

crates/runtime-config/src/lib.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use spin_factor_sqlite::runtime_config::spin as sqlite;
1616
use spin_factor_sqlite::SqliteFactor;
1717
use spin_factor_variables::{spin_cli as variables, VariablesFactor};
1818
use spin_factor_wasi::WasiFactor;
19+
use spin_factors::runtime_config::toml::GetTomlValue as _;
1920
use spin_factors::{
2021
runtime_config::toml::TomlKeyTracker, FactorRuntimeConfigSource, RuntimeConfigSourceFinalizer,
2122
};
@@ -33,6 +34,10 @@ pub struct ResolvedRuntimeConfig<T> {
3334
pub key_value_resolver: key_value::RuntimeConfigResolver,
3435
/// The resolver used to resolve sqlite databases from runtime configuration.
3536
pub sqlite_resolver: sqlite::RuntimeConfigResolver,
37+
/// The fully resolved state directory.
38+
///
39+
/// `None` is used for an "unset" state directory which each factor will treat differently.
40+
pub state_dir: Option<PathBuf>,
3641
}
3742

3843
impl<T> ResolvedRuntimeConfig<T>
@@ -41,6 +46,9 @@ where
4146
for<'a> <T as TryFrom<TomlRuntimeConfigSource<'a>>>::Error: Into<anyhow::Error>,
4247
{
4348
/// Creates a new resolved runtime configuration from a runtime config source TOML file.
49+
///
50+
/// `state_dir` is the explicitly provided state directory, if any. Some("") will be treated as
51+
/// as `None`.
4452
pub fn from_file(
4553
runtime_config_path: &Path,
4654
state_dir: Option<&str>,
@@ -64,21 +72,22 @@ where
6472
runtime_config_path.display()
6573
)
6674
})?;
67-
let runtime_config: T = TomlRuntimeConfigSource::new(
75+
let source = TomlRuntimeConfigSource::new(
6876
&toml,
69-
state_dir.unwrap_or(DEFAULT_STATE_DIR).into(),
77+
state_dir,
7078
&key_value_config_resolver,
7179
&tls_resolver,
7280
&sqlite_config_resolver,
7381
use_gpu,
74-
)
75-
.try_into()
76-
.map_err(Into::into)?;
82+
);
83+
let state_dir = source.state_dir();
84+
let runtime_config: T = source.try_into().map_err(Into::into)?;
7785

7886
Ok(Self {
7987
runtime_config,
8088
key_value_resolver: key_value_config_resolver,
8189
sqlite_resolver: sqlite_config_resolver,
90+
state_dir,
8291
})
8392
}
8493

@@ -102,24 +111,32 @@ where
102111
}
103112
Ok(())
104113
}
114+
115+
/// The fully resolved state directory.
116+
pub fn state_dir(&self) -> Option<PathBuf> {
117+
self.state_dir.clone()
118+
}
105119
}
106120

107121
impl<T: Default> ResolvedRuntimeConfig<T> {
122+
/// Creates a new resolved runtime configuration with default values.
108123
pub fn default(state_dir: Option<&str>) -> Self {
109124
let state_dir = state_dir.map(PathBuf::from);
110125
Self {
111126
sqlite_resolver: sqlite_config_resolver(state_dir.clone())
112127
.expect("failed to resolve sqlite runtime config"),
113-
key_value_resolver: key_value_config_resolver(state_dir),
128+
key_value_resolver: key_value_config_resolver(state_dir.clone()),
114129
runtime_config: Default::default(),
130+
state_dir,
115131
}
116132
}
117133
}
118134

119135
/// The TOML based runtime configuration source Spin CLI.
120136
pub struct TomlRuntimeConfigSource<'a> {
121137
table: TomlKeyTracker<'a>,
122-
state_dir: PathBuf,
138+
/// Explicitly provided state directory.
139+
state_dir: Option<&'a str>,
123140
key_value: &'a key_value::RuntimeConfigResolver,
124141
tls: &'a SpinTlsRuntimeConfig,
125142
sqlite: &'a sqlite::RuntimeConfigResolver,
@@ -129,7 +146,7 @@ pub struct TomlRuntimeConfigSource<'a> {
129146
impl<'a> TomlRuntimeConfigSource<'a> {
130147
pub fn new(
131148
table: &'a toml::Table,
132-
state_dir: PathBuf,
149+
state_dir: Option<&'a str>,
133150
key_value: &'a key_value::RuntimeConfigResolver,
134151
tls: &'a SpinTlsRuntimeConfig,
135152
sqlite: &'a sqlite::RuntimeConfigResolver,
@@ -144,6 +161,17 @@ impl<'a> TomlRuntimeConfigSource<'a> {
144161
use_gpu,
145162
}
146163
}
164+
165+
/// Get the configured state_directory.
166+
pub fn state_dir(&self) -> Option<PathBuf> {
167+
let from_toml = || self.table.get("state_dir").and_then(|v| v.as_str());
168+
// Prefer explicitly provided state directory, then take from toml.
169+
self.state_dir
170+
.or_else(from_toml)
171+
// Treat "" as None.
172+
.filter(|s| !s.is_empty())
173+
.map(PathBuf::from)
174+
}
147175
}
148176

149177
impl FactorRuntimeConfigSource<KeyValueFactor> for TomlRuntimeConfigSource<'_> {
@@ -187,7 +215,7 @@ impl FactorRuntimeConfigSource<OutboundMysqlFactor> for TomlRuntimeConfigSource<
187215

188216
impl FactorRuntimeConfigSource<LlmFactor> for TomlRuntimeConfigSource<'_> {
189217
fn get_runtime_config(&mut self) -> anyhow::Result<Option<spin_factor_llm::RuntimeConfig>> {
190-
llm::runtime_config_from_toml(self.table.as_ref(), self.state_dir.clone(), self.use_gpu)
218+
llm::runtime_config_from_toml(self.table.as_ref(), self.state_dir(), self.use_gpu)
191219
}
192220
}
193221

crates/trigger/src/cli.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use spin_common::ui::quoted_path;
1010
use spin_common::url::parse_file_url;
1111
use spin_common::{arg_parser::parse_kv, sloth};
1212
use spin_factors_executor::{ComponentLoader, FactorsExecutor};
13-
use spin_runtime_config::{ResolvedRuntimeConfig, DEFAULT_STATE_DIR};
13+
use spin_runtime_config::ResolvedRuntimeConfig;
1414

1515
use crate::factors::{TriggerFactors, TriggerFactorsRuntimeConfig};
1616
use crate::stdio::{FollowComponents, StdioLoggingExecutorHooks};
@@ -321,13 +321,14 @@ impl<T: Trigger> TriggerAppBuilder<T> {
321321
.await?;
322322

323323
let factors = TriggerFactors::new(
324-
options.state_dir.unwrap_or(DEFAULT_STATE_DIR),
324+
runtime_config.state_dir(),
325325
self.working_dir.clone(),
326326
options.allow_transient_write,
327327
runtime_config.key_value_resolver,
328328
runtime_config.sqlite_resolver,
329329
use_gpu,
330-
);
330+
)
331+
.context("failed to create factors")?;
331332

332333
// TODO: move these into Factor methods/constructors
333334
// let init_data = crate::HostComponentInitData::new(

crates/trigger/src/factors.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::path::PathBuf;
22

3+
use anyhow::Context as _;
34
use spin_factor_key_value::KeyValueFactor;
45
use spin_factor_llm::LlmFactor;
56
use spin_factor_outbound_http::OutboundHttpFactor;
@@ -31,14 +32,14 @@ pub struct TriggerFactors {
3132

3233
impl TriggerFactors {
3334
pub fn new(
34-
state_dir: impl Into<PathBuf>,
35+
state_dir: Option<PathBuf>,
3536
working_dir: impl Into<PathBuf>,
3637
allow_transient_writes: bool,
3738
default_key_value_label_resolver: impl spin_factor_key_value::DefaultLabelResolver + 'static,
3839
default_sqlite_label_resolver: impl spin_factor_sqlite::DefaultLabelResolver + 'static,
3940
use_gpu: bool,
40-
) -> Self {
41-
Self {
41+
) -> anyhow::Result<Self> {
42+
Ok(Self {
4243
wasi: wasi_factor(working_dir, allow_transient_writes),
4344
variables: VariablesFactor::default(),
4445
key_value: KeyValueFactor::new(default_key_value_label_resolver),
@@ -49,11 +50,11 @@ impl TriggerFactors {
4950
mqtt: OutboundMqttFactor::new(NetworkedMqttClient::creator()),
5051
pg: OutboundPgFactor::new(),
5152
mysql: OutboundMysqlFactor::new(),
52-
llm: LlmFactor::new(spin_factor_llm::spin::default_engine_creator(
53-
state_dir.into(),
54-
use_gpu,
55-
)),
56-
}
53+
llm: LlmFactor::new(
54+
spin_factor_llm::spin::default_engine_creator(state_dir, use_gpu)
55+
.context("failed to configure LLM factor")?,
56+
),
57+
})
5758
}
5859
}
5960

0 commit comments

Comments
 (0)