Add project files.

This commit is contained in:
2025-08-18 17:11:43 +03:30
parent 807dc263be
commit e5eb10d604
3943 changed files with 223719 additions and 0 deletions
@@ -0,0 +1,19 @@
# 1. Record architecture decisions
Date: 2025-04-01
## Status
Accepted
## Context
We need to record the architectural decisions made on this project.
## Decision
We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).
## Consequences
See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools).
@@ -0,0 +1,23 @@
# 2. Fault Propagation from Child to Parent Activities
Date: 2025-04-01
## Status
Accepted
## Context
When an activity throws an exception during execution, the `ExceptionHandlingMiddleware` is responsible for handling the fault. In addition to logging the exception and recording an incident, it also explicitly faults all ancestor activities using the `GetAncestors()` method and calling `TransitionTo(ActivityStatus.Faulted)` on each one.
At the time of implementing this behavior, the rationale was likely to bubble up the fault status to allow Elsa Studio to display that a given activity has one or more faulting descendant activities.
However, this behavior causes unintended side effects when the faulted activity is later resumed and completes successfully. Since the parent (e.g., a `Flowchart`) was faulted earlier, it remains in a `Faulted` state, unaware that the child it depends on has now succeeded. As a result, the Flowchart itself never reaches `Completed`, and the entire workflow instance is stuck in `Faulted` or `Running`, depending on the selected fault strategy.
## Decision
A new field will be introduced that represents an aggregate count of the faults occurring in descendant activities.
## Consequences
- Allows composite activities to reflect a failed state immediately and consistently when one of their children fails.
## Alternatives Considered
- Query descendants at runtime to get an aggregate fault count instead. However, this is an expensive operation that can be time consuming.
@@ -0,0 +1,40 @@
# 3. Direct Bookmark Management in WorkflowExecutionContext
Date: 2025-04-01
## Status
Accepted
## Context
Currently, `ActivityExecutionContext` maintains a temporary list of bookmarks created by the activity during its execution. After the activity completes, a middleware is responsible for copying these bookmarks into the `WorkflowExecutionContext.Bookmarks` list, which is then persisted to the database.
This architecture leads to a subtle issue upon resumption:
- When a workflow is resumed from a persisted state, only the `WorkflowExecutionContext` and its `Bookmarks` are restored from the database.
- The `ActivityExecutionContext`'s temporary `Bookmarks` list remains empty.
- As a result, if the resumed activity attempts to cancel (or modify) its previously created bookmarks, it cannot, because it has no access to them—changes are not tracked.
However, there is an existing convention that determines that if an activity created a bookmark during its execution, the activity will not automatically complete.
Specifically, this is implemented in the `AutoCompleteBehavior`, which is installed by the `CodeActivity` and possibly by custom activities.
To keep this behavior in tact, we will still maintain a private list of bookmarks, one that is explicitly purposed for maintaining *new** bookmarks, temporarily for the lifetime of the ActivityExecutionContext in memory.
## Decision
Eliminate the temporary `Bookmarks` list in `ActivityExecutionContext`. Instead, have activities add bookmarks directly to the `WorkflowExecutionContext.Bookmarks` list.
This is possible and safe because each `Bookmark` already contains:
- A reference to the originating `ActivityId`
- A reference to the originating `ActivityInstanceId`
These references allow accurate tracking and filtering of bookmarks, even when multiple activities are active.
Additionally, maintain a new temporary bookmarks list that explicitly stores newly created bookmarks. This list does not have to be copied into the WorkflowExecutionContext's Bookmarks property, given that this property will now be updated directly.
## Consequences
- Simplifies the architecture by removing the need for middleware to copy bookmarks post-execution.
- Fixes a bug where resumed activities could not cancel their previously created bookmarks.
- Reduces the chance of inconsistencies between temporary and persisted bookmark state.
- Ensures bookmark changes are always applied to the persisted, canonical source of truth.
## Alternatives Considered
- Keep the existing temporary list and enhance the system to hydrate the `ActivityExecutionContext.Bookmarks` list on resume. Rejected due to added complexity and duplication of state.
@@ -0,0 +1,28 @@
# 4. Activity Execution Snapshots
**Date:** 2025-08-04
**Status:** Accepted
## Context
Today the `ActivityExecutionContext` is persisted only at *commit points*.
If an activity references a workflow variable that changes after it has run—but before the next commit—the value saved is the *later* value, not the one that existed when the activity executed.
As a result, the Workflow Instance Viewer shows misleading data: users expect to see the variable values *at execution time*, not at commit time.
## Decision
Capture a **snapshot** of the `ActivityExecutionContext` immediately when an activity executes.
The snapshot must include:
* All workflow variables and their values at that moment.
* Any other execution-specific metadata required for replay or inspection.
The snapshot is created by serializing the `ActivityExecutionRecord` to JSON and storing it in the database.
The persistence layer will be updated to handle this new snapshot field, ensuring it is stored alongside the activity execution record.
## Consequences
* The Workflow Instance Viewer will now display the exact state that the activity saw, eliminating confusion during debugging and auditing.
* Additional storage will be consumed for each snapshot. We accept this overhead in exchange for correctness and developer experience.
* Existing persistence schemas will require a non-breaking migration to store the snapshot payload.
* Workflow instances before this change will not have snapshots, but they will still be replayable even if the variable values are not accurate at execution time.
+23
View File
@@ -0,0 +1,23 @@
# 5. Tenant Deleted Event
Date: 2025-08-05
## Status
Accepted
## Context
As outlined in issue [#6661](https://github.com/elsa-workflows/elsa-core/issues/6661), there is a need to differentiate between **Tenant Deactivating** and **Tenant Deleting** events.
Currently, the `TenantDeactivated` event is used to unregister timer-based triggers. However, this causes the triggers to be unregistered when the application host shuts down, which is not the desired behavior. Instead, we want the triggers to remain registered until the tenant is explicitly deleted.
## Decision
To address this, we will introduce a new event called `TenantDeleted`. This event will be raised when a tenant is deleted and will be responsible for unregistering timer-based triggers. This ensures that the triggers remain active until the tenant is explicitly deleted.
## Consequences
- Timer-based triggers will no longer be unregistered during tenant deactivation. Instead, they will remain active until the tenant is deleted.
- The `TenantDeactivated` event will continue to be used for deactivating tenants without affecting the registration of timer-based triggers.
- The new `TenantDeleted` event will specifically handle the cleanup of resources associated with a tenant when it is deleted, ensuring a clear separation of responsibilities.
+14
View File
@@ -0,0 +1,14 @@
digraph {
node [shape=plaintext];
subgraph {
_1 [label="1. Record architecture decisions"; URL="0001-record-architecture-decisions.html"];
_2 [label="2. Fault Propagation from Child to Parent Activities"; URL="0002-fault-propagation-from-child-to-parent-activities.html"];
_1 -> _2 [style="dotted", weight=1];
_3 [label="3. Direct Bookmark Management in WorkflowExecutionContext"; URL="0003-direct-bookmark-management-in-workflowexecutioncontext.html"];
_2 -> _3 [style="dotted", weight=1];
_4 [label="4. Activity Execution Snapshots"; URL="0004-activity-execution-snapshots.html"];
_3 -> _4 [style="dotted", weight=1];
_5 [label="5. Tenant Deleted Event"; URL="0005-tenant-deleted-event.html"];
_4 -> _5 [style="dotted", weight=1];
}
}
+7
View File
@@ -0,0 +1,7 @@
# Architecture Decision Records
* [1. Record architecture decisions](0001-record-architecture-decisions.md)
* [2. Fault Propagation from Child to Parent Activities](0002-fault-propagation-from-child-to-parent-activities.md)
* [3. Direct Bookmark Management in WorkflowExecutionContext](0003-direct-bookmark-management-in-workflowexecutioncontext.md)
* [4. Activity Execution Snapshots](0004-activity-execution-snapshots.md)
* [5. Tenant Deleted Event](0005-tenant-deleted-event.md)