Skip to content

Commit c3266c8

Browse files
ldanilekConvex, Inc.
authored and
Convex, Inc.
committed
update COMPONENTS_ENABLED gating (#27529)
update components code to go through the same path regardless of whether components are enabled. if there are is no document for root component metadata, and we're querying the root component or its definition, return the default data (ComponentType::App or an empty ComponentDefinitionMetadata). this allows us to start using components in prod without worrying about data getting out of sync. we don't need to backfill anything to get started with components. note if there is no component metadata, you can't call function in child components, but i think that's expected. this change is tested pretty well by existing tests, since i'm opening up the components codepaths to always run, instead of hiding them behind an env variable GitOrigin-RevId: 0ceaf2a57ab6df701f25764cdcd4c3e1edf299b3
1 parent 74e03b3 commit c3266c8

File tree

7 files changed

+96
-102
lines changed

7 files changed

+96
-102
lines changed

crates/common/src/bootstrap_model/tables.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ use value::{
1010
TableNumber,
1111
};
1212

13-
use crate::{
14-
components::COMPONENTS_ENABLED,
15-
types::{
16-
FieldName,
17-
TableName,
18-
},
13+
use crate::types::{
14+
FieldName,
15+
TableName,
1916
};
2017

2118
pub static TABLES_TABLE: LazyLock<TableName> =
@@ -158,10 +155,6 @@ fn table_namespace_from_serialized(
158155
fn table_namespace_to_serialized(
159156
m: TableNamespace,
160157
) -> anyhow::Result<Option<SerializedTableNamespace>> {
161-
anyhow::ensure!(
162-
*COMPONENTS_ENABLED || matches!(m, TableNamespace::Global),
163-
"non-global namespaces should only be serialized when components are enabled"
164-
);
165158
match m {
166159
TableNamespace::Global => Ok(None),
167160
TableNamespace::ByComponent(id) => Ok(Some(SerializedTableNamespace::ByComponent {

crates/common/src/components/mod.rs

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,6 @@ pub use self::{
3535
pub static COMPONENTS_ENABLED: LazyLock<bool> =
3636
LazyLock::new(|| env_config("COMPONENTS_ENABLED", false));
3737

38-
pub fn require_components_enabled() -> anyhow::Result<()> {
39-
if !*COMPONENTS_ENABLED {
40-
anyhow::bail!("Components are not enabled, set COMPONENTS_ENABLED=true to enable them.");
41-
}
42-
Ok(())
43-
}
44-
4538
// Globally unique system-assigned ID for a component.
4639
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
4740
pub enum ComponentId {
@@ -72,16 +65,9 @@ impl ComponentId {
7265

7366
impl From<ComponentId> for TableNamespace {
7467
fn from(value: ComponentId) -> Self {
75-
if *COMPONENTS_ENABLED {
76-
match value {
77-
ComponentId::Root => TableNamespace::root_component(),
78-
ComponentId::Child(id) => TableNamespace::ByComponent(id),
79-
}
80-
} else {
81-
match value {
82-
ComponentId::Root => TableNamespace::Global,
83-
ComponentId::Child(_id) => TableNamespace::Global,
84-
}
68+
match value {
69+
ComponentId::Root => TableNamespace::root_component(),
70+
ComponentId::Child(id) => TableNamespace::ByComponent(id),
8571
}
8672
}
8773
}

crates/database/src/bootstrap_model/components/mod.rs

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use std::{
88
use anyhow::Context;
99
use common::{
1010
bootstrap_model::components::{
11-
definition::ComponentDefinitionMetadata,
11+
definition::{
12+
ComponentDefinitionMetadata,
13+
ComponentDefinitionType,
14+
},
1215
ComponentMetadata,
1316
ComponentType,
1417
},
@@ -35,6 +38,7 @@ use common::{
3538
runtime::Runtime,
3639
types::IndexName,
3740
};
41+
use errors::ErrorMetadata;
3842
use value::{
3943
DeveloperDocumentId,
4044
FieldPath,
@@ -261,28 +265,67 @@ impl<'a, RT: Runtime> BootstrapComponentsModel<'a, RT> {
261265
Ok(result)
262266
}
263267

268+
pub async fn load_component_type(&mut self, id: ComponentId) -> anyhow::Result<ComponentType> {
269+
match self.load_component(id).await? {
270+
None => {
271+
if id.is_root() {
272+
// The root component's metadata document may be missing if the app hasn't been
273+
// updated to use components.
274+
Ok(ComponentType::App)
275+
} else {
276+
anyhow::bail!(ErrorMetadata::bad_request(
277+
"InvalidReference",
278+
format!("Component {:?} not found", id),
279+
))
280+
}
281+
},
282+
Some(component) => Ok(component.into_value().component_type),
283+
}
284+
}
285+
264286
pub async fn load_definition(
265287
&mut self,
266288
id: ComponentDefinitionId,
267-
) -> anyhow::Result<ParsedDocument<ComponentDefinitionMetadata>> {
289+
) -> anyhow::Result<Option<ParsedDocument<ComponentDefinitionMetadata>>> {
268290
let internal_id = match id {
269-
ComponentDefinitionId::Root => {
270-
let root_component = self
271-
.root_component()
272-
.await?
273-
.context("Missing root component")?;
274-
root_component.definition_id
291+
ComponentDefinitionId::Root => match self.root_component().await? {
292+
Some(root_component) => root_component.definition_id,
293+
None => return Ok(None),
275294
},
276295
ComponentDefinitionId::Child(id) => id,
277296
};
278297
let component_definition_doc_id = self.resolve_component_definition_id(internal_id)?;
279-
let doc: ParsedDocument<ComponentDefinitionMetadata> = self
280-
.tx
298+
self.tx
281299
.get(component_definition_doc_id)
282300
.await?
283-
.context("Missing component definition")?
284-
.try_into()?;
285-
Ok(doc)
301+
.map(TryInto::try_into)
302+
.transpose()
303+
}
304+
305+
pub async fn load_definition_metadata(
306+
&mut self,
307+
id: ComponentDefinitionId,
308+
) -> anyhow::Result<ComponentDefinitionMetadata> {
309+
match self.load_definition(id).await? {
310+
Some(doc) => Ok(doc.into_value()),
311+
None => {
312+
if id.is_root() {
313+
// The root component's metadata document may be missing if the app hasn't been
314+
// updated to use components.
315+
Ok(ComponentDefinitionMetadata {
316+
path: ComponentDefinitionPath::root(),
317+
definition_type: ComponentDefinitionType::App,
318+
child_components: Vec::new(),
319+
exports: BTreeMap::new(),
320+
})
321+
} else {
322+
anyhow::bail!(ErrorMetadata::bad_request(
323+
"InvalidReference",
324+
format!("Component definition {:?} not found", id),
325+
))
326+
}
327+
},
328+
}
286329
}
287330

288331
pub async fn load_all_definitions(

crates/isolate/src/environment/action/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,6 @@ impl<RT: Runtime> ActionEnvironment<RT> {
250250
let (task_retval_sender, task_responses) = mpsc::unbounded();
251251
let resources = Arc::new(Mutex::new(BTreeMap::new()));
252252
let task_executor = TaskExecutor {
253-
component: component.clone(),
254253
rt: rt.clone(),
255254
identity: identity.clone(),
256255
file_storage,

crates/isolate/src/environment/action/phase.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use common::{
1010
ComponentPath,
1111
Reference,
1212
Resource,
13-
COMPONENTS_ENABLED,
1413
},
1514
runtime::{
1615
Runtime,
@@ -162,16 +161,12 @@ impl<RT: Runtime> ActionPhase<RT> {
162161
let source_package = SourcePackageModel::new(&mut tx, component_id.into())
163162
.get_latest()
164163
.await?;
165-
if !*COMPONENTS_ENABLED {
166-
anyhow::ensure!(self.component.is_root());
167-
} else {
168-
let loaded_resources = ComponentsModel::new(&mut tx)
169-
.preload_resources(component_id)
170-
.await?;
171-
{
172-
let mut resources = resources.lock();
173-
*resources = loaded_resources;
174-
}
164+
let loaded_resources = ComponentsModel::new(&mut tx)
165+
.preload_resources(component_id)
166+
.await?;
167+
{
168+
let mut resources = resources.lock();
169+
*resources = loaded_resources;
175170
}
176171
Ok((module_metadata, source_package))
177172
})

crates/isolate/src/environment/action/task_executor.rs

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@ use std::{
77
use common::{
88
components::{
99
ComponentFunctionPath,
10-
ComponentPath,
1110
Reference,
1211
Resource,
13-
COMPONENTS_ENABLED,
1412
},
1513
execution_context::ExecutionContext,
1614
http::fetch::FetchClient,
@@ -67,7 +65,6 @@ use crate::{
6765
pub struct TaskExecutor<RT: Runtime> {
6866
pub rt: RT,
6967
pub identity: Identity,
70-
pub component: ComponentPath,
7168
pub file_storage: TransactionalFileStorage<RT>,
7269
pub syscall_trace: Arc<Mutex<SyscallTrace>>,
7370
pub action_callbacks: Arc<dyn ActionCallbacks>,
@@ -196,17 +193,7 @@ impl<RT: Runtime> TaskExecutor<RT> {
196193
}
197194

198195
pub fn resolve(&self, reference: &Reference) -> anyhow::Result<Resource> {
199-
let resource = if !*COMPONENTS_ENABLED {
200-
match reference {
201-
Reference::Function(p) if self.component.is_root() => {
202-
Resource::Function(ComponentFunctionPath {
203-
component: ComponentPath::root(),
204-
udf_path: p.clone(),
205-
})
206-
},
207-
r => anyhow::bail!("Invalid reference {r:?} with components disabled"),
208-
}
209-
} else {
196+
let resource = {
210197
let resources = self.resources.lock();
211198
resources
212199
.get(reference)

crates/model/src/components/mod.rs

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,10 @@ impl<'a, RT: Runtime> ComponentsModel<'a, RT> {
5656
[attribute] => attribute,
5757
_ => anyhow::bail!("Nested component argument references unsupported"),
5858
};
59-
let component = BootstrapComponentsModel::new(self.tx)
60-
.load_component(component_id)
61-
.await?
62-
.ok_or_else(|| {
63-
ErrorMetadata::bad_request(
64-
"InvalidReference",
65-
format!("Component {:?} not found", component_id),
66-
)
67-
})?;
68-
let ComponentType::ChildComponent { ref args, .. } = component.component_type
69-
else {
59+
let component_type = BootstrapComponentsModel::new(self.tx)
60+
.load_component_type(component_id)
61+
.await?;
62+
let ComponentType::ChildComponent { ref args, .. } = component_type else {
7063
anyhow::bail!(ErrorMetadata::bad_request(
7164
"InvalidReference",
7265
"Can't use an argument reference in the app"
@@ -160,7 +153,7 @@ impl<'a, RT: Runtime> ComponentsModel<'a, RT> {
160153
) -> anyhow::Result<Resource> {
161154
let mut m = BootstrapComponentsModel::new(self.tx);
162155
let definition_id = m.component_definition(component_id).await?;
163-
let definition = m.load_definition(definition_id).await?;
156+
let definition = m.load_definition_metadata(definition_id).await?;
164157

165158
let mut current = &definition.exports;
166159
let mut attribute_iter = attributes.iter();
@@ -193,19 +186,15 @@ impl<'a, RT: Runtime> ComponentsModel<'a, RT> {
193186
component_id: ComponentId,
194187
) -> anyhow::Result<BTreeMap<Reference, Resource>> {
195188
let mut m = BootstrapComponentsModel::new(self.tx);
196-
let component = m.load_component(component_id).await?.ok_or_else(|| {
197-
ErrorMetadata::bad_request(
198-
"InvalidReference",
199-
format!("Component {:?} not found", component_id),
200-
)
201-
})?;
189+
let component = m.load_component(component_id).await?;
190+
let component_type = m.load_component_type(component_id).await?;
202191
let definition_id = m.component_definition(component_id).await?;
203-
let definition = m.load_definition(definition_id).await?;
192+
let definition = m.load_definition_metadata(definition_id).await?;
204193
let component_path = m.get_component_path(component_id).await?;
205194

206195
let mut result = BTreeMap::new();
207196

208-
if let ComponentType::ChildComponent { ref args, .. } = component.component_type {
197+
if let ComponentType::ChildComponent { ref args, .. } = component_type {
209198
for (name, resource) in args {
210199
let reference = Reference::ComponentArgument {
211200
attributes: vec![name.clone()],
@@ -236,21 +225,23 @@ impl<'a, RT: Runtime> ComponentsModel<'a, RT> {
236225
}
237226
}
238227

239-
for instantiation in &definition.child_components {
240-
let parent = (component.id().internal_id(), instantiation.name.clone());
241-
let child_component = BootstrapComponentsModel::new(self.tx)
242-
.component_in_parent(Some(parent))
243-
.await?
244-
.context("Missing child component")?;
245-
let child_component_id = ComponentId::Child(child_component.id().internal_id());
246-
for (attributes, resource) in
247-
self.preload_exported_resources(child_component_id).await?
248-
{
249-
let reference = Reference::ChildComponent {
250-
component: instantiation.name.clone(),
251-
attributes,
252-
};
253-
result.insert(reference, resource);
228+
if let Some(component) = component {
229+
for instantiation in &definition.child_components {
230+
let parent = (component.id().internal_id(), instantiation.name.clone());
231+
let child_component = BootstrapComponentsModel::new(self.tx)
232+
.component_in_parent(Some(parent))
233+
.await?
234+
.context("Missing child component")?;
235+
let child_component_id = ComponentId::Child(child_component.id().internal_id());
236+
for (attributes, resource) in
237+
self.preload_exported_resources(child_component_id).await?
238+
{
239+
let reference = Reference::ChildComponent {
240+
component: instantiation.name.clone(),
241+
attributes,
242+
};
243+
result.insert(reference, resource);
244+
}
254245
}
255246
}
256247

@@ -263,7 +254,7 @@ impl<'a, RT: Runtime> ComponentsModel<'a, RT> {
263254
) -> anyhow::Result<BTreeMap<Vec<Identifier>, Resource>> {
264255
let mut m = BootstrapComponentsModel::new(self.tx);
265256
let definition_id = m.component_definition(component_id).await?;
266-
let definition = m.load_definition(definition_id).await?;
257+
let definition = m.load_definition_metadata(definition_id).await?;
267258

268259
let mut stack = vec![(vec![], &definition.exports)];
269260
let mut result = BTreeMap::new();

0 commit comments

Comments
 (0)