Source code for simstack.core.recompute_artifacts
import logging
from simstack.core.artifacts import ArtifactArguments, create_artifacts
from simstack.core.context import context
from simstack.core.definitions import TaskStatus
from simstack.core.node import node_from_database
from simstack.models import NodeRegistry, ArtifactModel
from simstack.models.charts_artifact import ChartArtifactModel
from simstack.models.table_artifact import TableArtifactModel
from simstack.util.importer import import_class
from simstack.util.importer import import_function
logger = logging.getLogger("recompute_artifacts")
[docs]
async def recompute_artifacts(node_registry: NodeRegistry):
"""
Recomputes artifacts for a node and all its children recursively.
First processes all children nodes recursively, then removes and recomputes
the current node's artifacts.
:param node_registry: The registry entry for the node to process
:type node_registry: NodeRegistry
"""
# Create Node from the registry
db = context.db
node = await node_from_database(node_registry)
if node is None:
logger.error(f"Failed to create node from registry task_id: {node_registry.id}")
return
if node.status != TaskStatus.COMPLETED:
logger.error(f"Cannot recompute artifacts for task_id: {node_registry.id} name: {node.name} status: {node.status}")
return
# Find all children of this node
children = await db.find(NodeRegistry, NodeRegistry.parent_ids.in_([node_registry.id]))
# Recursively recompute artifacts for all children first
for child_registry in children:
await recompute_artifacts(child_registry)
# Remove current node's artifacts
table_artifacts = await db.find(
TableArtifactModel, TableArtifactModel.parent_id == node_registry.id
)
for table_artifact in table_artifacts:
await db.delete(table_artifact)
chart_artifacts = await db.find(
ChartArtifactModel, ChartArtifactModel.parent_id == node_registry.id
)
for chart_artifact in chart_artifacts:
await db.delete(chart_artifact)
if node_registry.artifact_ids:
logger.info(f"Removing {len(node_registry.artifact_ids)} artifacts for node {node_registry.id}")
# Delete artifacts from the database
for artifact_id in node_registry.artifact_ids:
instance = await db.find_one(
ArtifactModel, ArtifactModel.id == artifact_id
)
if instance:
await db.delete(instance)
else:
logger.warning(
f"task_id: {node_registry.id} Failed to delete artifact {artifact_id} from database"
)
node_registry.artifact_ids = []
# Recompute artifacts for this node
if node_registry.status == TaskStatus.COMPLETED:
logger.info(f"Recomputing artifacts for node {node_registry.id} {node_registry.name}")
# Load the result to create new artifacts
result = await node.load_results()
if result is not None:
artifact_arguments = ArtifactArguments(result, node_registry.id)
# Reconstruct the function arguments for artifact creation
args = []
for ref in node_registry.input_references:
model = await import_class(ref.variable_mapping, context.db)
arg = await db.find_one(model, model.id == ref.reference)
if arg:
args.append(arg)
# Get the function for artifact creation
wrapped_func = await import_function(node_registry.func_mapping, context.db)
func = (
wrapped_func
if not hasattr(wrapped_func, "_inner")
else wrapped_func._inner
)
# Create node kwargs similar to run_local
node_kwargs = {
"parent_id": node_registry.id,
"task_id": node_registry.id,
"call_path": node_registry.call_path,
"parent_parameters": node_registry.parameters,
}
artifact_arguments.add_attributes(func, *args, **node_kwargs)
node_registry.artifact_ids = await create_artifacts(artifact_arguments, node_registry)
# Save the updated registry
await db.save(node_registry)
logger.info(
f"Recomputed {len(node_registry.artifact_ids)} artifacts for node {node_registry.id}"
)
else:
logger.warning(
f"Node {node_registry.id} is not completed, cannot recompute artifacts"
)