Commit graph

130 commits

Author SHA1 Message Date
Sipke Schoorstra c2fb027c41
Refactor: Overhauls workflow JSON type serialization (#7549)
* Avoid null endpoint DTO metadata in tests

* Enforce console logs hub read permission

* Remove unused console logs hub import

* Support mapped endpoint metadata in auth tests

* Reduce console log capture throughput impact

* Address Copilot console logs review

* Refactor task scheduling to support tenant-level background work and enhance logging functionality.

* Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage.

* Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly.

* Add Ansi SGR parser for console logs and associated unit tests

* Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support.

* Address console logs code quality feedback

* Address PR review feedback

* Preserve console logs extension points

* Stabilize console logs host lifecycle

* Address final automated review comments

* Tighten console log capture shutdown

* Address console log review feedback

* Address follow-up review feedback

* Cover final review feedback

* Avoid recursive console provider initialization

* Guard console host lease shutdown

* Preserve console log scope and provider lifetime

* Correlate console log scope fallback

* Tighten console scope correlation

* Expose host services during provider construction

* Redact ANSI-normalized console lines

* Remove `ConsoleCaptureTee` and related services and tests

* Use pipeline contributors for console log context

* Update CShells package versions to 0.0.24-preview.132

* Filter live console logs by workflow instance

* Enhance console logging with activity execution metadata and extend test coverage.

* Address console logs stream consumption comment

* Add diagnostics OpenTelemetry backend

* Introduce dedicated workflow JSON type registry and hardening

This change addresses GitHub issue #7541 by establishing a separate type registry (`IWorkflowJsonTypeRegistry`) for workflow JSON serialization. This decouples workflow type resolution from expression type aliases, enforcing a strict trust boundary.

Key aspects:
- New workflow JSON emits preferred aliases for registered types.
- Existing persisted workflows can be loaded via registered legacy names.
- Unknown, abstract, interface, open generic, or inappropriate collection types are rejected during deserialization, enhancing security.
- Public APIs (e.g., incident strategies) now expose consistent workflow JSON type identifiers.

This ensures secure, predictable, and backward-compatible handling of types within workflow definitions and payloads.

* Remove unused project references and streamline console log endpoint

* Move serialization type aliases to Elsa.Common

* Update serialization integration fixtures for aliases

* Stabilize missing rate limiter policy test
2026-05-31 11:09:39 +02:00
Sipke Schoorstra 842cf7c162
[codex] Fix console log metadata and type resolution (#7542)
* Avoid null endpoint DTO metadata in tests

* Enforce console logs hub read permission

* Remove unused console logs hub import

* Support mapped endpoint metadata in auth tests

* Reduce console log capture throughput impact

* Address Copilot console logs review

* Refactor task scheduling to support tenant-level background work and enhance logging functionality.

* Introduce ConsoleStreamHook for stdout/stderr tee and enhance logging validation. Adjust test cases and startup warnings for distributed lock provider usage.

* Refactor console logging pipeline with capture optimization and new ConsoleLogsHost; update tests accordingly.

* Add Ansi SGR parser for console logs and associated unit tests

* Remove ANSI color renderings and parsers; integrate ConsoleLogScopeAccessor for improved logging context with workflow instance ID support.

* Address console logs code quality feedback

* Address PR review feedback

* Preserve console logs extension points

* Stabilize console logs host lifecycle

* Address final automated review comments

* Tighten console log capture shutdown

* Address console log review feedback

* Address follow-up review feedback

* Cover final review feedback

* Avoid recursive console provider initialization

* Guard console host lease shutdown

* Preserve console log scope and provider lifetime

* Correlate console log scope fallback

* Tighten console scope correlation

* Expose host services during provider construction

* Redact ANSI-normalized console lines

* Add OpenTelemetry diagnostics backend foundation

* Add OTLP HTTP ingestion parsing

* Document OpenTelemetry diagnostics setup

* Enforce OpenTelemetry hub permissions

* Remove `ConsoleCaptureTee` and related services and tests

* Add OpenTelemetry HTTP ingestion integration test

* Use pipeline contributors for console log context

* Update CShells package versions to 0.0.24-preview.132

* Add OpenTelemetry ingestion security tests

* Add OpenTelemetry API authorization tests

* Filter live console logs by workflow instance

* Add OpenTelemetry hub tests

* Add OpenTelemetry gRPC metadata hook

* Assert OpenTelemetry workflow tags survive ingestion

* Mark OpenTelemetry core build verified

* Enhance console logging with activity execution metadata and extend test coverage.

* Address console logs stream consumption comment

* Wire OpenTelemetry diagnostics into core sample

* Address Core diagnostics review feedback

* Address Core Copilot follow-up feedback

* Add OpenTelemetry metric instrument names

* Address Core Copilot provider feedback

* Address Core Copilot diagnostics follow-up

* Address Core Copilot live feed feedback

* Address Core Copilot store feedback

* Integrate OpenTelemetry for logging, tracing, and metrics in ModularServer and update launch settings and docker-compose configuration.

* Refactor to replace `ConsoleLogStream.Core` with `ConsoleLogStreaming.Core` across codebase and update `ConsoleStreamHook` installation.

* Add diagnostics OpenTelemetry backend

* Fix OpenTelemetry live hub subscription

* Fix modular OpenTelemetry exporter endpoints

* Add CShells logging configuration in appsettings.json

* Remove obsolete unit tests and helper classes

* Restore default activity exception handling

* Simplify type serialization and alias management

This commit refactors the internal type serialization and alias management system to reduce boilerplate, improve robustness, and simplify the developer experience:

-   Removed numerous explicit `ExpressionOptions` type alias registrations across various modules.
-   Updated `TypeJsonConverter` and polymorphic serialization to reliably handle types using assembly-qualified names when a short alias is not explicitly registered.
-   Streamlined `ExcludeFromHashConverter` to strictly adhere to `ExcludeFromHashAttribute` for hash calculations, removing complex `JsonIgnoreCondition` logic.
-   Eliminated several helper classes (`WorkflowJsonTypeResolver`, `WorkflowTypeValidator`, `IWorkflowTypeRegistry`, `WorkflowFactoryDictionary`, `JavaScriptExceptionTypeAliasRegistrar`, `WorkflowRuntimeTypeAliasRegistrar`) and their associated unit tests, simplifying the codebase.

Additionally, this commit introduces a comprehensive markdown document (`product-website-feature-source.md`) outlining Elsa's core features, Studio capabilities, extension ecosystem, and architectural selling points, intended as source material for the product website.

* Refine type serialization for improved robustness and alias handling

This commit further enhances the type serialization and deserialization mechanisms:

*   Centralizes type resolution and alias management through `IWellKnownTypeRegistry` and `WorkflowJsonTypeResolver`.
*   Prioritizes registered type aliases when serializing type metadata in `PolymorphicObjectConverter`, resulting in more concise JSON output.
*   Enhances deserialization in `PolymorphicObjectConverter` and `VariableMapper` to gracefully handle unknown or non-instantiable types, providing fallbacks and logging warnings.
*   Simplifies `TypeJsonConverter` by delegating complex type resolution logic to the `WorkflowJsonTypeResolver`.
*   Adds `JsonArray` to the well-known type aliases for direct recognition.

* Fix console logs packaging and workflow type resolution

* Fix console log metadata and type resolution

* Address Copilot review feedback

* Enhance type resolution, improve console log handling, and update tests

- Streamlined `WorkflowDictionaryExtensions` for better workflow registration validation.
- Refined `ConsoleLogsAuthorizationTests` with the new `SetJsonRequest` helper to improve test requests handling.
- Updated `OrderDefinition` to ignore JSON serialization for `KeySelector`.
- Enhanced `WorkflowRuntimeFeature` for improved workflow registration and type alias configuration.
- Added tests to ensure `ConsoleLogProvider` metadata filtration in various scenarios.
- Improved type serialization logic in `WorkflowJsonTypeResolver`.
- Updated README to fix references related to diagnostics.
- Optimized `ExcludeFromHashConverter` for property serialization conditions.
- Modified `TriggerIndexer` for streamlined trigger management.
- Tested payload checks in `PublishEventTests`.
- Adjusted `Endpoint` in `ConsoleLogs` for automatic JSON request handling.
- Ensured registration of workflow type aliases in `WorkflowsFeature`.

* Restore CLR workflow registration compatibility

* Align JSON island serialization fixtures

* Add Console Logs Services and Enhance Endpoint Handling

- Introduced `ActivityExecutionsEndpointTests` to validate route exposure.
- Added `ConsoleLogCaptureHostedService` for console log streaming.
- Implemented `ConsoleStreamJsonConverter` for JSON conversion of console streams.
- Developed `ElsaConsoleLogRecentBuffer` to handle recent log buffering.
- Updated `ConsoleLogsAuthorizationTests` with new test cases for stream filter mapping.
- Consolidated console log provider dependencies and registration, including recent buffering.
- Enhanced `ElsaConsoleLogProvider` to use recent buffer for filtering.
- Adjusted `Program.cs` for streamlined logging service setup.

* Enhance type resolution and test coverage; streamline console log integration

- Added `ConsoleStreamHook` for streamlined log streaming.
- Updated `WorkflowJsonTypeResolverTests` to improve type resolution and test new scenarios.
- Simplified type resolution by removing trusted assembly checks.

* Fix CI smoke and package restore failures

* Fix Docker smoke image project paths

* Fix Docker Python runtime packages

* Fix Docker CA smoke teardown

* Refresh Elsa roadmap

* Implement background processors and mediation coordination

- Added `BackgroundCommandProcessor`, `BackgroundJobProcessor`, and `BackgroundNotificationProcessor` classes for handling commands, jobs, and notifications, respectively.
- Introduced `MediatorBackgroundProcessingCoordinator` to coordinate the execution of all background processors.
- Implemented `MediatorBackgroundTask` for wrapping `MediatorBackgroundProcessingCoordinator` in `BackgroundTask`.
- Added unit tests for `MediatorBackgroundTask` to ensure proper start and stop behavior.
- Refactored `BackgroundCommandSenderHostedService` to utilize `BackgroundCommandProcessor`.
- Introduced 'elsa-roadmap-refresh' skill configuration for roadmap updates.

* Address workflow type resolution review feedback

* Address follow-up review feedback

* Restore recent console logs execute path

* Address Copilot follow-up review

* Decouple workflow JSON aliases from expressions

* Fix workflow management unit test setup

* Fix console logs recent endpoint handler shape

* Respect workflow JSON strict type aliases

* Remove unused console log contracts reference

* Address Copilot review feedback

* Address Copilot follow-up comments

* Synchronize ring buffer dropped count

* Address background processor strategy replay
2026-05-30 22:52:01 +02:00
Sipke Schoorstra cec3281a20
[codex] Harden workflow JSON type resolution (#7499)
* Harden workflow JSON type resolution

* Harden workflow type alias serialization

* Register JSON island type aliases

* Fix workflow JSON aliases for runtime types

* Register CLR workflow type aliases at startup

* Register safe workflow serialization aliases

* Use registered workflow type aliases in serializers

* Restore trusted legacy workflow JSON aliases

* Share runtime workflow type alias registration

* Address workflow JSON review follow-ups

* Address workflow JSON review follow-ups

* Address workflow JSON review edge cases

* Address workflow JSON converter review feedback

* Register workflow JSON types for HTTP and JavaScript failures

* Address secure type serialization review comments

* Address deserialization review feedback

* Address workflow serialization review comments

* Address workflow type review feedback

* Tighten workflow type hardening fixes

* Avoid workflow alias string type resolution

* Address workflow type alias review feedback

* Stabilize publish event payload assertion

* Stabilize bulk dispatch component test

* Make workflow dictionary aliases idempotent

* Declare workflow runtime feature dependency

* Assert trigger payload alias serialization

* Import workflow helper contracts

* Avoid duplicate CLR workflow materialization

* Normalize workflow factory aliases
2026-05-22 15:25:49 +02:00
Sipke Schoorstra d09a1b7cb4
Add workflow dispatch transactional outbox (#7517)
* Add workflow dispatch transactional outbox

* Address workflow dispatch outbox review

* Make outbox state lookup null-safe

* Generate stable outbox dispatch instance ids

* Limit eager outbox processing to marked commits

* Avoid blocking eager outbox processing on lock contention

* Expire uncommitted outbox items after retention

* Harden eager workflow outbox processing

* Prune delivered workflow outbox markers

* Batch workflow dispatch outbox processing

* Bound workflow dispatch outbox processing batches

* Harden workflow dispatch outbox processing

* Address transactional outbox review feedback

* Address transactional outbox follow-up review

* Address outbox recovery review feedback

* Address outbox key-value review fixes

* Address outbox cleanup review feedback

* Address workflow outbox review feedback

* Address outbox key-value review feedback

* Preserve outbox key-value tenant ids

* Address workflow outbox marker cleanup review

* Ensure key value store factory registrations override

* Address workflow outbox review follow-ups
2026-05-22 00:13:16 +02:00
Sipke Schoorstra 96b5ee80b5
Add bookmark queue dead-letter store (#7516)
* Add bookmark queue dead-letter store

* Make bookmark dead-letter replay atomic

* Address bookmark dead-letter review feedback

* Restore dead-letter replay state on enqueue failure

* Preserve replay rollback during cancellation

* Address bookmark dead-letter review threads

* Fix Oracle runtime migration snapshot drift

* Address bookmark dead-letter review feedback

* Make bookmark dead-lettering idempotent

* Detach memory dead-letter store snapshots

* Address bookmark dead-letter review fixes

* Harden bookmark dead-letter replay responses

* Preserve failed dead-letter replay during purge

* Clarify workflow runtime store list

* Address bookmark dead-letter review feedback

* Refine bookmark dead-letter purge races
2026-05-21 23:43:36 +02:00
Sipke Schoorstra 26b17e35e2
Refactor QuiescenceSignal to inject IServiceScopeFactory, enhance tenant ID handling, and expand unit tests with DI capabilities. 2026-05-03 17:56:37 +02:00
Sipke Schoorstra d7bdbfb26d
Graceful shutdown for the workflow runtime (drain, pause, recover) (#7424)
* feat(workflows-runtime): add quiescence machinery foundation for graceful shutdown

Introduces the container-scoped quiescence signal, ingress-source contract,
burst registry, and the Interrupted workflow sub-status — the foundational
primitives the drain orchestrator and admin endpoints will build on. No
behaviour change yet: workflows continue to run and shut down exactly as
before. The new types are registered but no host-stop or pause path drives
them.

Highlights:
* IQuiescenceSignal — composable Drain + AdministrativePause flags;
  forward-only drain, reversible pause, idempotent transitions, optional
  persistence via IKeyValueStore.
* IIngressSource + IForceStoppable — uniform contract for components that
  inject external events (HTTP, schedulers, message consumers, internal
  workers, third-party modules); IIngressSourceRegistry collects and
  surfaces their states.
* IBurstRegistry — atomic counter for in-flight workflow execution
  bursts, with per-burst ingress attribution and FR-018 inconsistency
  detection (a source claiming Paused but starting bursts is flipped to
  PauseFailed).
* WorkflowSubStatus.Interrupted — new value distinct from Suspended,
  Cancelled, Faulted; semantics: "last burst force-cancelled by graceful
  drain; resumable on next runtime generation". Mirrored on the API client
  enum.
* GracefulShutdownOptions — drain deadline, per-source pause timeout,
  stimulus-queue back-pressure policy, pause-persistence policy.
  Configurable via UseWorkflowRuntime(...).ConfigureGracefulShutdown(...).
* PermissionNames.ManageWorkflowRuntime — single permission for the
  forthcoming admin pause/resume/status/force endpoints.

Implements 31 of 77 tasks for the graceful-shutdown feature
(specs/002-graceful-shutdown). Subsequent commits add the drain
orchestrator (US1 / MVP), Interrupted recovery scan (US3), admin
endpoints (US2), and first-party ingress adapters.

Tests: 25 new xUnit unit tests; 100/100 runtime unit tests pass; all
existing tests continue to pass on net8.0/net9.0/net10.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(workflows-runtime): add drain orchestrator + host-stop integration (US1, MVP)

When the host receives a stop signal (SIGTERM, Ctrl+C, orchestrator
rollout), the runtime now drains gracefully: ingress sources are paused
in parallel, in-flight workflow bursts run to their next natural
persistence boundary within a configurable deadline, and any burst that
breaches the deadline is force-cancelled and persisted with the
Interrupted sub-status plus a forensic WorkflowInterrupted log entry.

This is the MVP — without the activation-time recovery scan (PR 3) the
existing timeout-based RestartInterruptedWorkflowsTask still picks up
Interrupted instances, just on its periodic cadence. No regression in
that recovery path (SC-008).

Highlights:
* IDrainOrchestrator + DrainOrchestrator — protocol per the contract:
  BeginDrainAsync → parallel ingress pause with per-source timeouts +
  IForceStoppable escalation → poll BurstRegistry.ActiveCount until zero
  or deadline → on breach iterate live handles, cancel, persist
  Interrupted, write log entry. All exceptions are captured into the
  returned DrainOutcome; only second-invocation throws.
* Deadline clamping: effective deadline is min(GracefulShutdownOptions.
  DrainDeadline, HostOptions.ShutdownTimeout - 500ms safety epsilon),
  so the runtime never outlives its host process.
* DrainOrchestratorHostedService — IHostedService.StopAsync wakes the
  orchestrator on host stop. Registered AFTER the heartbeat
  (Elsa.Hosting.Management) so reverse-order shutdown keeps the
  heartbeat alive throughout drain. Prevents sibling-node crash recovery
  from false-positive-recovering instances we are gracefully handling
  here (FR-029).
* BurstTrackingMiddleware — workflow-execution-pipeline middleware that
  registers a BurstHandle for the lifetime of every burst. All nine
  IWorkflowRunner.RunAsync overloads ultimately funnel into
  pipeline.ExecuteAsync(context), so this single middleware covers the
  three "burst choke points" the spec references without nine separate
  decorators. Added to UseDefaultPipeline().
* Ingress attribution: optional IngressSourceName property on
  DispatchStimulusRequest, DispatchWorkflowDefinitionRequest, and
  DispatchWorkflowInstanceRequest. Adapters set it; the middleware reads
  it via WorkflowExecutionContext.TransientProperties (helpers in
  IngressAttributionExtensions). The BurstRegistry uses the name to
  detect the FR-018 invariant violation — a source that reports Paused
  but starts a burst is flipped to PauseFailed.
* InterruptedLogExtensions — the LogWorkflowInterruptedAsync helper
  that the orchestrator calls when persisting the forensic record.

Tests: 11 new unit tests (DrainOrchestrator parallel-pause +
wait-for-bursts + idempotency + persistence-failure path); 5 new
integration tests (full DI graph resolves, burst-tracking middleware
registers handles end-to-end, no-op drain returns
CompletedWithinDeadline). 100/100 runtime unit tests pass; all
existing tests continue to pass on net8.0/net9.0/net10.0.

Implements 14 of 77 tasks (T032–T045). Subsequent commits add
Interrupted recovery scan (US3), admin endpoints (US2), and
first-party ingress adapters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(admin-endpoints): add admin endpoints for workflow runtime control

Introduced admin endpoints to manage workflow runtime: `/pause`, `/resume`, `/status`, and `/force` with full authentication and audit logging. Integrated idempotency checks and error handling to ensure reliable runtime control. Added corresponding integration tests for verification.

* fix(workflows-runtime): propagate drain cancellation into running workflows + initialize persisted pause + fix log-comment

Addresses three findings from the PR #7424 code review:

1. **HIGH — Cancellation now propagates into the running workflow.**
   `BurstHandle.Cancel()` previously cancelled only its own linked CTS,
   which the workflow runner never observes (the runner reads from
   `WorkflowExecutionContext.CancellationToken`, captured at context
   construction and not part of the linked chain). On deadline breach
   the orchestrator would persist `Interrupted`, but the workflow
   continued executing and could overwrite the sub-status with whatever
   terminal state it eventually reached.

   Fix: `BurstHandle` accepts an optional cancel callback at construction.
   `BurstTrackingMiddleware` wires it to `context.Cancel()` so the burst's
   cancellation triggers the workflow's own cancellation chain — the
   workflow transitions to `Cancelled` and stops scheduling new
   activities. The orchestrator then awaits `BurstHandle.Disposed` (with
   a 2 s settle timeout) before persisting `Interrupted`, ensuring the
   runner's terminal commit completes BEFORE the orchestrator overwrites
   the sub-status. Race resolved.

   The settle timeout is bounded so a non-cancellable activity (genuinely
   pathological case) does not block drain — on timeout the orchestrator
   logs and proceeds, accepting the runner-clobber for that one
   instance, which the existing timeout-based RestartInterruptedWorkflows
   recovery picks up afterwards.

2. **MEDIUM — Pause persistence is now actually wired.**
   `QuiescenceSignal.InitializePersistedStateAsync` was implemented but
   nothing called it on host startup. A host configured with
   `PausePersistence = AcrossReactivations` would write the persisted
   key on pause, but on subsequent activation the new
   `QuiescenceSignal` instance would never read it, so the runtime would
   resume dispatching despite the operator having paused.

   Fix: `InitializePauseStateStartupTask : IStartupTask` reads the policy
   and calls `InitializePersistedStateAsync` once per activation when the
   policy demands it. Registered in both `WorkflowRuntimeFeature`
   flavours alongside the other graceful-shutdown services.

3. **MEDIUM — Comment in `DrainOrchestrator.PersistInterruptedAsync` no
   longer lies.** The previous comment promised a "synthetic log entry"
   that the next statement (`return`) prevented from being written. The
   comment is now honest about what actually happens: when no instance
   row exists, no log entry is emitted, but the burst metadata is still
   captured in the drain outcome's logged warning so operators have a
   forensic trail.

Tests:
* New unit tests on `BurstRegistry` (now 9, was 6): cancel-callback is
  invoked, callback exceptions are swallowed (drain remains best-effort),
  `BurstHandle.Disposed` completes on dispose.
* Full suites continue to pass: 103/103 runtime unit tests; 247/247
  workflow integration tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime): address PR review feedback + close runner-clobber race + add e2e drain test

Six issues raised in PR #7424 review (one e2e gap, five comments inline):

1. **Runner-clobber race closed via ICommitStateHandler decorator.**
   The previous fix wired `BurstHandle.Cancel()` to `WorkflowExecutionContext.Cancel()`
   so the workflow's cancellation chain fires on deadline breach, but the e2e
   test exposed that `BurstHandle` disposed at the END of the pipeline middleware
   (i.e., BEFORE `WorkflowRunner` calls `commitStateHandler.CommitAsync`). The
   orchestrator's `await handle.Disposed` therefore returned too early, the
   instance row didn't yet exist, and the orchestrator's Interrupted write was
   either a no-op (no row) or got clobbered by the runner's subsequent Cancelled
   commit.

   Fix: `BurstAwareCommitStateHandler` decorates `ICommitStateHandler`. The
   middleware no longer disposes the handle in the success path — it stores
   the handle in `WorkflowExecutionContext.TransientProperties`, and the
   decorator disposes it AFTER `inner.CommitAsync` completes. The exception
   path in the middleware still disposes for safety. Result: the orchestrator's
   await-disposed sequencing now correctly lands the Interrupted write last.

2. **C1: Null-instance log entry.** `DrainOrchestrator.PersistInterruptedAsync`
   now writes a synthetic `WorkflowInterrupted` log entry directly when no
   instance row exists, populating only the fields it knows. Previously the
   forensic trail was lost.

3. **C2: Force endpoint cached-outcome audit.** Added `WasCached` flag to
   `DrainOutcome` (default false). The orchestrator sets it on the cached
   return path (`_previousOutcome with { WasCached = true }`). The force
   endpoint now skips the audit notification when the flag is true, so
   repeated force calls no longer emit spurious `RuntimeForceRequested` events
   (SC-007 idempotency restored).

4. **C3: `StateChanged` raised under lock — deadlock risk closed.**
   `QuiescenceSignal.BeginDrainAsync`/`PauseAsync`/`ResumeAsync` now do their
   transitions under the lock, capture whether a transition occurred, release
   the lock, and only then invoke `RaiseStateChanged`. Subscribers that
   synchronously call back into the signal can no longer deadlock.

5. **C4: Scheduling source name.** Renamed `scheduling.cron` → `scheduling.triggers`
   to honestly reflect the four trigger types the adapter covers (Cron, Timer,
   StartAt, Delay). The name is surfaced verbatim in admin status responses.

6. **C5: Hardcoded Retry-After.** `HttpWorkflowsMiddleware`'s 503 response now
   sets a reason-aware `Retry-After`: 5 s during drain (host is exiting and
   will be replaced shortly), 60 s during administrative pause (indefinite,
   so a longer back-off avoids tight retry loops).

Tests:
* New e2e `DeadlineBreachEndToEndTests` (2 tests): verifies that drain
  against a real running workflow detects the in-flight burst, force-cancels
  it, persists the instance as `Interrupted`, and writes a `WorkflowInterrupted`
  log entry — closing the test gap that hid the cancellation-propagation
  issue identified in the previous review pass.
* Updated `OperatorForceAfterPreviousReturnsCachedOutcome` to assert
  value-equality + the `WasCached` flag instead of reference-equality
  (records use `with` for the cached return path).

Full suites pass: 103/103 runtime unit, 249/249 workflow integration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(workflows-api): move runtime admin endpoints into Elsa.Workflows.Api

Per PR review feedback: rather than introducing a new sub-module
(Elsa.Workflows.Runtime.Admin) for the four pause/resume/status/force
endpoints, fold them into the existing Elsa.Workflows.Api project. That
project already references both Elsa.Workflows.Runtime and
Elsa.Api.Common (FastEndpoints) and is the established home for
client-facing workflow APIs — so the admin endpoints belong there.

Changes:
* New folder src/modules/Elsa.Workflows.Api/Endpoints/RuntimeAdmin/ with
  Models.cs and Pause/Resume/Status/Force/Endpoint.cs. Namespaces moved
  from `Elsa.Workflows.Runtime.Admin` → `Elsa.Workflows.Api.Endpoints.RuntimeAdmin`.
* Deleted src/modules/Elsa.Workflows.Runtime.Admin/ entirely and removed
  it from Elsa.sln. The ShellFeature marker class
  (WorkflowRuntimeAdminFeature) is no longer needed — the existing
  WorkflowsApiFeature already discovers FastEndpoints in the Workflows.Api
  assembly.
* No consumer changes: the endpoints sit in the same routes
  (/admin/workflow-runtime/*) and behave identically.

Note on the second architectural point ("update IShellFeature if cleaner"):
the IShellFeature contract is defined in the external CShells NuGet
package, not in this repo, so we cannot add a DeactivateAsync hook
without an upstream CShells change. The current IHostedService.StopAsync
hook continues to work correctly for the host-stop path; per-shell
deactivation would require either a CShells upstream addition or a
separate Elsa-owned shell-feature variant — neither lighter than what we
have today.

Tests: 103/103 runtime unit + 249/249 workflow integration pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(common): introduce IsFatal exception extension + apply to drain best-effort catches

Per PR review feedback on the static-analyzer "Generic catch clause"
comments: rather than catching ALL exceptions in best-effort drain code
paths, narrow the swallow to non-fatal exceptions. Process-fatal
conditions (StackOverflowException, AccessViolationException,
SEHException, ThreadAbortException, OutOfMemoryException) propagate so
the host's failure-fast policy can act on them, while normal failures
(InvalidOperationException, IOException, etc.) continue to be logged
and allowed through so a single misbehaving ingress source / activity
cannot abort the overall drain.

Highlights:
* New `Elsa.Common.Extensions.ExceptionExtensions.IsFatal` utility:
  classifies fatal conditions, unwraps reflection-style wrappers
  (TypeInitializationException, TargetInvocationException) before
  classification, and treats InsufficientMemoryException (the
  recoverable OOM subclass) as non-fatal.
* Applied as a `when (!ex.IsFatal())` filter to:
    - BurstHandle.Cancel (cancel callback try/catch)
    - DrainOrchestrator.PauseOneSourceAsync (per-source exception path)
    - DrainOrchestrator.TryForceStopAsync
    - DrainOrchestrator.ForceCancelActiveBurstsAsync (per-burst loop)
    - DrainOrchestrator.PersistInterruptedAsync (orphan log write,
      instance save, log write)
    - DrainOrchestrator.DrainAsync outer catch (existing
      `not InvalidOperationException` filter extended)
    - InterruptedRecoveryScan (per-instance restart loop)

Tests: 7 new unit tests for IsFatal classification (fatal types,
recoverable types, wrapped causes, null tolerance). Full suites:
103/103 runtime unit (incl. 14/14 in Common.UnitTests including new
tests) + 249/249 workflow integration pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(workflows-runtime): integrate CShells 0.0.15 lifecycle hooks (IDrainHandler + IShellInitializer)

CShells 0.0.15 ships the lifecycle framework needed for first-class per-shell
graceful shutdown — IDrainHandler / IShellInitializer / IShellLifecycleSubscriber.
This commit bumps the package, migrates Elsa's existing usage of the removed
0.0.14 API, and registers the runtime drain orchestrator + pause-state initializer
through the new primitives.

Highlights:
* `ElsaShellDrainHandler : IDrainHandler` — bridges per-shell drain into
  `IDrainOrchestrator.DrainAsync(DrainTrigger.ShellDeactivation, ct)`. Invoked
  by CShells when a shell enters `ShellLifecycleState.Draining`; the drain
  handler's CancellationToken is signalled when the per-shell deadline elapses,
  so the orchestrator's own deadline-bounded protocol nests cleanly.
  Coexists with the host-stop `DrainOrchestratorHostedService`; the
  orchestrator's `DrainAsync` is idempotent — second invocations log and skip.
* `InitializePauseStateShellInitializer : IShellInitializer` — replaces the
  IStartupTask variant in shell-aware deployments. IShellInitializer fires on
  EVERY shell (re)activation, including reactivations after a reload — exactly
  what FR-028 requires. The IStartupTask remains for IModule consumers where
  there is no shell platform.

Migrations (CShells 0.0.14 → 0.0.15 breaking changes):
* `ActivateShellTenants`: was `IShellActivatedHandler` + `IShellDeactivatingHandler`,
  now `IShellInitializer` + `IDrainHandler`.
* `MultitenancyFeature`: registrations updated to the new transient interface,
  `using CShells.Hosting` → `using CShells.Lifecycle`.
* `Reload/Endpoint`, `ReloadAll/Endpoint`: `IShellManager` → `IShellRegistry`,
  `ReloadShellAsync` → `ReloadAsync` (returns `ReloadResult` with `Error`),
  `ReloadAllShellsAsync` → `ReloadActiveAsync` (returns
  `IReadOnlyList<ReloadResult>` with per-shell errors aggregated into 503).

Build + restore:
* `Directory.Packages.props`: all CShells.* packages bumped to 0.0.15.
* `NuGet.Config`: added `cshells-feedz` source
  (https://f.feedz.io/sfmskywalker/cshells/nuget/index.json) and split the
  package-source-mapping pattern into `CShells` (exact) + `CShells.*`
  (prefix). Single-pattern `CShells*` does NOT match correctly under
  PackageSourceMapping.

Tests: 103/103 runtime unit + 249/249 workflow integration pass on the new
package version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(workflows-runtime): apply PR #7424 review feedback

Consolidates the architectural fixes asked for during /review:

- Extract IWorkflowRuntimeAdminService to back the four /admin/workflow-runtime endpoints with a single domain service; thin Pause/Resume/Status/Force endpoints to delegating shells.
- Remove StateChanged C# event from IQuiescenceSignal (Constitution VII: no external subscribers existed; mediator was suggested as the alternative if/when it's needed).
- Promote InitializePersistedStateAsync to IQuiescenceSignal, dropping the concrete-cast in both InitializePauseStateStartupTask and InitializePauseStateShellInitializer.
- Invert ingress-source DI to Lazy<IEnumerable<IIngressSource>> to break the cycle through IQuiescenceSignal; ingress adapters take the signal directly via primary constructor.
- Replace Guid.NewGuid().ToString("N") with IIdentityGenerator in InterruptedLogExtensions and DrainOrchestrator.
- Switch admin-audit timestamps to ISystemClock in WorkflowRuntimeAdminService.
- Make GracefulShutdownOptions.StimulusQueueMaxDepthWhilePaused nullable (null = unlimited).
- Rename RuntimeForceRequested → RuntimeForceDrainRequested.
- Apply IsFatal exception filter to drain best-effort catches.
- Rename IBurstRegistry.EnumerateActive → ListActiveBursts.
- Refresh "Phase X" comments to user-story (USx) references.
- Delete unused IngressAttributionExtensions, IngressSourceServiceCollectionExtensions, IngressSourceRegistrationOptions.
- Migrate Elsa.Shells.Api.Tests to CShells 0.0.15 IShellRegistry / ReloadResult surface.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(graceful-shutdown): apply IsFatal filter to deadline-breach test catch

Aligns the test scaffolding's swallow-everything catch with the project standard introduced in c00eee80c so the analyzer no longer flags the bare `catch` clause. The semantics are unchanged — non-fatal exceptions (OCE, TimeoutException, workflow exceptions) are still acceptable test outcomes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime): close IngressSourceRegistry first-access race + spelling

Replaces the non-atomic `_entries.Count > 0` early-return guard in
EnsureMaterialized with a double-checked lock against a volatile
`_materialized` flag, so concurrent first callers can no longer both
iterate the source factory and crash one of them with a "Duplicate ingress
source registration" InvalidOperationException. Adds a regression test that
launches 16 readers behind a TaskCompletionSource gate and asserts every
reader observes the full source set without throwing.

Also flips the British spellings introduced in this PR's scope to American
English (materialize/behavior) — project convention going forward.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(constitution): require American English for new code (v1.0.1)

Adds a "Spelling & language" bullet under principle III (Convention-Driven Design): every newly-introduced symbol, comment, identifier, error message, XML doc, commit message, and Speckit artifact uses American English. Established public API symbols (e.g. WorkflowSubStatus.Cancelled) are not renamed retroactively. PATCH bump because this is a clarification of an existing principle, not a new principle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add Greploop skill and workflow for GitLab, GitHub, and Perforce integration

- Introduced Greploop, an iterative optimization and review workflow for GitLab MRs, GitHub PRs, and Perforce changelists.
- Added API and GraphQL references for fetching and resolving review skill.

* Remove GenerateWorkflowVariableAccessorsTests; redundant ExpandoObject type check in handlers

* Potential fix for pull request finding 'CodeQL / Untrusted Checkout TOCTOU'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix(graceful-shutdown): apply PR #7424 review feedback round 2

Two P1 findings from Greptile:

1. DrainOrchestrator.ForceCancelActiveBurstsAsync was sequential — each
   burst was cancelled, awaited up to ForceCancelSettleTimeout (2 s), and
   persisted before the next burst's Cancel() ran. Total wall time was
   O(N × 2 s) and bursts 2..N kept executing at full speed during prior
   bursts' settle waits, defeating the intent of force-cancel under
   concurrency.

   Refactored to three phases:
   - Phase A — cancel every handle synchronously (cheap CTS.Cancel calls)
     so all runners observe cancellation simultaneously.
   - Phase B — await every Disposed signal in parallel under a single
     shared ForceCancelSettleTimeout. Total wall time bounded regardless
     of N.
   - Phase C — persist Interrupted for each handle sequentially (keeps
     DbContext usage single-threaded; per-handle work is small).

   Per-phase failures are caught with !ex.IsFatal() and logged so a single
   misbehaving handle doesn't abort the rest of the batch.

2. ShellFeatures/WorkflowRuntimeFeature.ConfigureServices was missing the
   IWorkflowRuntimeAdminService registration that Features/WorkflowRuntimeFeature
   already had. Any CShells deployment that includes the Pause / Resume /
   Status / Force admin endpoints (in Elsa.Workflows.Api) would throw
   InvalidOperationException at endpoint construction. Added the singleton
   alongside the other graceful-shutdown registrations with a comment
   pointing out the symmetry with the IModule path.

17/17 graceful-shutdown integration tests pass; 103/103 runtime unit tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Potential fix for pull request finding 'CodeQL / Untrusted Checkout TOCTOU'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* fix(ci): harden greploop.yml against CodeQL Actions findings

CodeQL flagged 12 findings on .github/workflows/greploop.yml after the
prior commit (c08183a3c) addressed an earlier round. Two distinct issue
classes remain:

1. Code injection (× ~10): step-output values
   (steps.pr_head.outputs.head_sha / head_repo_owner / head_repo_name /
   head_ref) and inputs.pr_number were interpolated directly into shell
   `run:` blocks via `${{ ... }}`. Because PR author controls the branch
   name and the manual-dispatch input, those values can carry shell
   metacharacters. Standard fix: route every such interpolation through
   an `env:` block on the step, then reference $VAR inside the script.
   Applied to the Resolve, Resolve PR head metadata, and Checkout PR
   branch steps.

2. Untrusted Checkout TOCTOU + Checkout of untrusted code in trusted
   context: the workflow runs on `issue_comment` (a privileged trigger)
   and checks out PR-author code. Mitigations stacked here:
   - Author-association gate already restricts the trigger to OWNER /
     MEMBER / COLLABORATOR (existing).
   - Step-output values now travel via env vars (above).
   - Resolve step rejects pr_number that isn't ^[0-9]{1,10}$ — so
     downstream `gh pr view` and the prompt argument can't be hijacked.
   - Checkout step now validates HEAD_SHA matches ^[0-9a-f]{40}$ and the
     repo owner/name match ^[A-Za-z0-9_.-]+$ before either reaches a
     URL or a git command.
   - Existing TOCTOU guard preserved: re-fetch head SHA at checkout
     time and abort if it changed since the initial resolve.

These match the canonical "Securing your GitHub Actions workflows"
patterns recommended by CodeQL.

No functional change to greploop's runtime behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(graceful-shutdown): drop [SingleNodeTask] from InitializePauseStateStartupTask

Greptile P1: [SingleNodeTask] gates the task to a single cluster winner via
distributed lock, but IQuiescenceSignal is a singleton scoped to each node's
DI container — each node holds its own in-memory QuiescenceState. With the
attribute, only the winning node restored the persisted pause; every other
node started with QuiescenceReason.None and accepted new work, silently
defeating PausePersistence = AcrossReactivations.

Removed [SingleNodeTask] (and the corresponding using) so the task runs on
every node. Expanded the doc <remarks> to call out the per-node requirement
and point at the shell-aware counterpart (InitializePauseStateShellInitializer)
which is correctly per-node by virtue of being an IShellInitializer.

17/17 graceful-shutdown integration tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Potential fix for pull request finding 'CodeQL / Code injection'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* chore(deps): bump CShells 0.0.15 → 0.0.17

0.0.17 ships our blueprint-aware-routing PR (valence-works/cshells#93) plus
four follow-up fixes the maintainer added on top:

- e56ebd8 — PreWarmShells removed entirely; ShellMiddleware now does
  cold-start endpoint matching (re-runs endpoint resolution after lazy
  activation so the very first request to a cold shell hits its endpoint).
- cbe5ee2 — GetCandidateSnapshot returns a bounded ShellRouteCandidateSnapshot
  with accurate total counts; sensitive-data redaction in routing logs;
  DefaultShellRouteIndex implements IDisposable.
- cd7d4f5 — Last-good snapshot served on rebuild failure (the deferred
  Copilot review concern); root-path fallback when path-by-name misses.
- c3679d9 — Cold-start endpoint matching respects inline route constraints;
  path-name convention tightening; dead duplicate-detection cleanup.

Net effect for elsa-core:
- Cold blueprints serve their first request via lazy activation, with
  endpoints correctly resolved post-activation.
- Reloaded shells re-activate and serve on the next matched request.
- Non-name-mode routing keeps serving the previous snapshot during a
  transient blueprint-provider outage.
- No need to call PreWarmShells from Elsa.ModularServer.Web — removed.

The only API removal that touches elsa-core is PreWarmShells. No code
references IShellRouteIndex / ShellRouteCriteria / GetCandidateSnapshot
directly, so the API-shape changes in cbe5ee2 don't ripple here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(graceful-shutdown): persist Interrupted under non-drain bounded token

Greptile P? finding on the prior force-cancel two-phase fix: Phase B's
inner catch on OperationCanceledException ("drain CT fired — proceed to
persist anyway") was a lie in practice. Phase C immediately passed the
same already-cancelled drain token into PersistInterruptedAsync; the
first DB call (instanceStore.FindAsync) observed the cancellation and
threw OperationCanceledException; the outer non-fatal Exception filter
swallowed it and only logged an error. Net effect: on host shutdown
deadline breach, every burst after cancellation could fail to be
persisted as Interrupted, leaving instances in an unrecovered executing
state.

Phase C now creates a per-handle CancellationTokenSource bounded to a
new PersistInterruptedTimeout (5 s) that is NOT linked to the drain CT.
Each persist gets up to 5 s to land the row update + forensic log entry
even after the drain CT has fired. The bound prevents a stuck DB from
hanging shutdown indefinitely (per-handle worst case is small; total
Phase C upper bound is N × 5 s, but typical persists are millisecond
scale).

Comment expanded to call out why the persist token is independent of
the drain token, so the rationale doesn't drift again.

17/17 graceful-shutdown integration tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(graceful-shutdown): extract PassiveIngressSource base class

The three IIngressSource implementations that ship with this PR
(InternalBookmarkQueueIngressSource, HttpTriggerIngressSource,
ScheduledTriggerIngressSource) were ~25 lines each and ~22 lines of
those were verbatim copies of each other:

- ctor signature `(IQuiescenceSignal signal)`
- `PauseTimeout => TimeSpan.FromMilliseconds(50)`
- `CurrentState => signal.IsAcceptingNewWork ? Running : Paused`
- `PauseAsync` / `ResumeAsync` returning `ValueTask.CompletedTask`

The shared trait is that none of them does any work at pause time —
the actual pause enforcement lives in another layer
(`HttpWorkflowsMiddleware` short-circuits to 503,
`BookmarkQueueProcessor` consults the signal at the top of each
invocation, scheduled triggers dispatch through the bookmark queue and
inherit that behaviour transitively). The IIngressSource adapter is
purely diagnostic: it makes the source visible in
`DrainOutcome.Sources` and the admin status endpoint.

Extracted that pattern into `PassiveIngressSource` (abstract base in
`Elsa.Workflows.Runtime.IngressSources`). Subclasses now provide only
`Name`; `PauseTimeout` is `virtual` with a 50 ms default; everything
else is fixed by the base. The three concretes drop from ~25 lines to
~12 lines each.

The base's XML `<remarks>` calls out when to use it ("your component
already cooperates with IQuiescenceSignal at its hot path") and when
to implement IIngressSource directly ("the source owns concrete
pause/resume behaviour — e.g. a message-queue consumer that calls
Pause() on its underlying client"), so future contributors don't
mis-extend the base for sources that need real work at pause time.

No behavioural change. 18 graceful-shutdown integration + 39 runtime
unit tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(graceful-shutdown): align IIngressSource name to singular

The three IIngressSource names were inconsistent:

  http.trigger                       (singular)
  internal.bookmark-queue-worker     (singular)
  scheduling.triggers                (PLURAL — outlier)

The plural slipped in when addressing Greptile's earlier comment to
avoid `scheduling.cron` (which would imply Cron-only coverage). The
right move was to pick a generic word and stay singular like the rest
of the suite — the suite's mental model is "the X source", one
instance per registry slot, regardless of how many triggers or items
it dispatches internally.

Renamed to `scheduling.trigger`. The `<remarks>` block keeps the
"covers Cron, Timer, StartAt, Delay" explanation and now also
explicitly notes the singular convention so future contributors don't
re-pluralize.

Zero test fallout — the literal "scheduling.triggers" only appeared in
the source file itself. Tests of the other two sources all use
singular forms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(runtime-admin): rename Force endpoint to ForceDrain

"Force" alone is meaningless out of context — force what? — and it
sits oddly next to the verb-named siblings Pause / Resume / Status.
The matching admin service method is already IWorkflowRuntimeAdminService.
ForceDrainAsync, so ForceDrain is the natural pair.

Renamed:
- src/modules/Elsa.Workflows.Api/Endpoints/RuntimeAdmin/Force/        → ForceDrain/
- namespace ...Endpoints.RuntimeAdmin.Force                            → ...ForceDrain
- class ForceEndpoint                                                  → ForceDrainEndpoint
- class ForceRequest                                                   → ForceDrainRequest
- class ForceResponse                                                  → ForceDrainResponse
- route  POST /admin/workflow-runtime/force                            → /force-drain

Zero external references — no tests, docs, or OpenAPI clients used the
old symbols or the old route literal, so this is a contained pre-ship
rename. Directory move went through `git mv` so commit history follows
the file.

17/17 graceful-shutdown integration tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ci): correct formatting in checkout step within greploop.yml

Adjusted indentation of environment variables in the checkout step for improved consistency and readability.

* fix(ci): repair malformed Checkout repository step in greploop.yml

The step accumulated stray env keys, an extra `uses:`, and bash commands
that didn't belong inside it (line 65 onward), causing a YAML parse
error on push. The valid structure has two distinct checkout steps:

  - Checkout repository  : actions/checkout@v4 with fetch-depth: 0
  - Checkout PR branch   : env: + run: with SHA validation + git fetch
                            + git checkout --detach

The PR-branch step (line 78+) was already correct and unchanged. This
fix restores the first step to its intended single-purpose shape (just
checks out the workflow file's commit so the greploop skill is on disk
before the run-greploop step uses it).

No functional change to runtime behaviour or to the security posture
established in the prior hardening commit (0db4ca23e). The PR-branch
checkout still validates HEAD_SHA / HEAD_REPO_OWNER / HEAD_REPO_NAME
shape before they reach a URL or git command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ci): remove literal `${{ }}` from greploop.yml comment

GitHub Actions parses `${{ ... }}` workflow expressions across the entire
YAML file, including inside `run:` script comments. The comment that
explained the env-var hardening pattern contained the literal sequence
`${{ }}` (with a space, intended as an English-language description),
which the expression parser rejected as "An expression was expected"
(line 81 col 14).

Reworded the comment to describe the substitution form in prose without
the literal token sequence. Functional behaviour unchanged.

* refactor(graceful-shutdown): rename burst → execution cycle

The graceful-shutdown work introduced "burst of execution" as a
first-class domain concept. The term arrived without rationale and
isn't standard in the workflow-engine domain. Renamed to
"execution cycle" — reads more naturally as the loop-with-commit unit,
is more idiomatic in workflow vocabulary, pairs cleanly with the
existing WorkflowExecutionContext, and avoids collisions with Elsa's
existing terms (Run, Execution, Dispatch, Invocation, Stimulus, Step).

Renamed types
- IBurstRegistry              → IExecutionCycleRegistry
- BurstRegistry               → ExecutionCycleRegistry
- BurstHandle                 → ExecutionCycleHandle
- BurstTrackingMiddleware     → ExecutionCycleTrackingMiddleware
- BurstAwareCommitStateHandler → ExecutionCycleAwareCommitStateHandler

Renamed members
- BeginBurst                          → BeginCycle
- ListActiveBursts                    → ListActiveCycles
- BurstHandleKey constant + value     → ExecutionCycleHandleKey
- ActiveBurstCount (IQuiescenceSignal,
  RuntimeAdminStatus, StatusResponse) → ActiveExecutionCycleCount
- WaitForBurstsAsync (private)        → WaitForCyclesAsync
- ForceCancelActiveBurstsAsync (priv) → ForceCancelActiveCyclesAsync
- UseBurstTracking                    → UseExecutionCycleTracking
- DrainOutcomeDto.BurstsForceCancelledCount → ExecutionCyclesForceCancelledCount
- _burstRegistry / burstRegistry      → _cycleRegistry / cycleRegistry

Backwards-compatibility preservation (the only persisted JSON key)
- WorkflowInterruptedPayload.BurstDuration property → ExecutionCycleDuration
  with [JsonPropertyName("BurstDuration")] so the persisted JSON wire
  key stays "BurstDuration" forever. Pre-merge testers' log records
  still deserialise correctly. The contract test on
  WorkflowInterruptedPayloadContractTests still asserts the wire key
  "BurstDuration" appears in the serialised JSON — confirms the
  guarantee is enforced.

Other unstructured surfaces
- WorkflowExecutionLogRecord.Message text "Workflow burst was force-
  cancelled..." now says "Workflow execution cycle was force-cancelled
  ..." for new records. Old rows keep their old text — purely cosmetic
  free-text field.
- Structured log placeholder {BurstId} in DrainOrchestrator log lines
  → {ExecutionCycleId}.
- Lowercase prose / XML doc comments updated throughout.

Test renames
- BurstRegistryTests          → ExecutionCycleRegistryTests
- BurstTrackingMiddlewareTests → ExecutionCycleTrackingMiddlewareTests
- Test method names + DisplayName strings updated.

Spec docs (specs/002-graceful-shutdown/) updated to match the new
vocabulary; the historical task records in tasks.md keep the old names
as-is to preserve the audit trail of what was originally built.

Verification
- dotnet build: clean across net8.0 / net9.0 / net10.0.
- 103/103 Elsa.Workflows.Runtime.UnitTests pass.
- 17/17 GracefulShutdown integration tests pass.
- 4/4 WorkflowInterruptedPayloadContractTests pass — confirms the
  "BurstDuration" JSON wire-key preservation is intact.

No changes to migrations or DB column names — confirmed via grep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(ci): give greploop.yml gh-cli a repo context before checkout

The "Resolve PR head metadata" step runs `gh pr view` before
actions/checkout, so there is no `.git` directory and gh's "current
repo" detection fails with `fatal: not a git repository`. The
prior commits to this file masked the runtime failure because the
workflow itself was YAML-invalid — once it became valid, the
workflow_dispatch trigger surfaced this real-world execution bug.

Set GH_REPO=${{ github.repository }} on both `gh pr view` steps. The
gh CLI honours GH_REPO as an explicit repo override, so it no longer
needs git context. Same fix on the "Checkout PR branch" validation
call which also uses gh pr view before the manual fetch.

The error reported as "Invalid workflow file: ... (Line 81 Col 14)"
on PR #7424 was stale from commit ed580682a (which had the bad
comment with literal `${{ }}`); commit 3a8ad0d08 fixed the YAML, but
because greploop's `if:` condition only matches workflow_dispatch /
issue_comment events, push events on later commits were skipped
without re-running validation, so the GitHub UI kept showing the
old error. A workflow_dispatch run on the current SHA now passes
validation and reaches "Resolve PR head metadata", which is what
this commit fixes.

* fix(graceful-shutdown): wire IngressPauseTimeout option to drain orchestrator

GracefulShutdownOptions.IngressPauseTimeout was documented as "Default
per-ingress-source pause timeout" but DrainOrchestrator.PauseOneSourceAsync
read source.PauseTimeout directly and never consulted the option. The
configured value was silently ignored — operators who set
GracefulShutdownOptions:IngressPauseTimeout = 10s were getting whatever
each source's hardcoded value was (50 ms for the three PassiveIngressSource
subclasses we ship), with no way to tune it globally.

Precedence (per the spec's intent of "overridable at registration and by
configuration"):

  1. Per-source positive value wins (source.PauseTimeout > Zero).
  2. Otherwise fall back to the configured GracefulShutdownOptions.
     IngressPauseTimeout default.
  3. Resolved value is capped at the overall drain deadline so a single
     misbehaving source cannot exceed the host's shutdown budget.
  4. 1 ms safety floor remains so a misconfigured zero default still
     produces a non-zero CancelAfter.

Changes:

- DrainOrchestrator.PauseOneSourceAsync — adds the precedence above with
  a comment block explaining each step.
- IIngressSource.PauseTimeout — XML doc clarifies the Zero-defers-to-
  config semantics.
- GracefulShutdownOptions.IngressPauseTimeout — XML doc says it's the
  fallback when the source returns Zero; <remarks> spells out the
  precedence and the overall-deadline cap.
- PassiveIngressSource.PauseTimeout — virtual property now returns Zero
  (was 50 ms). The three shipped subclasses (HttpTriggerIngressSource,
  ScheduledTriggerIngressSource, InternalBookmarkQueueIngressSource)
  consequently defer to the configured default — flipping the wire-up
  bug from "configured value silently ignored" to "configured value
  honoured by default for passive sources". Passive subclasses that
  want a specific value can still override.

103/103 runtime unit + 17/17 graceful-shutdown integration tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(graceful-shutdown): rename IInterruptedRecoveryScan → IInterruptedRecoveryScanner

The interface had a single verb-method (`ScanAndRequeueAsync`) and its
XML doc described what it *does* ("Scans the workflow instance store
for instances..."). That's an agent role — a scanner that performs a
scan — but the noun-shaped name `IInterruptedRecoveryScan` read as
"the scan itself", which is misleading because the scan results /
event are not first-class types in the codebase.

Renamed to `IInterruptedRecoveryScanner` / `InterruptedRecoveryScanner`
to match the existing `-er` convention in this codebase (Restarter,
Generator, Resolver, etc.). The method stays `ScanAndRequeueAsync` —
the scanner *performs* a scan-and-requeue.

Also renamed the constructor parameter `scan` → `scanner` in
RecoverInterruptedWorkflowsStartupTask, and the local variable `scan`
→ `scanner` in InterruptedRecoveryIntegrationTests, so the "scanner
does the scan" mental model is consistent throughout.

Surface impact (all internal — no API or persistence touch points):
- 2 source files renamed via git mv (interface + implementation)
- 1 test file renamed (InterruptedRecoveryScanTests → ScannerTests)
- DI registrations in both Features/ and ShellFeatures/ WorkflowRuntimeFeature
- 1 startup-task constructor parameter
- Spec doc references under specs/002-graceful-shutdown/

103/103 runtime unit + 17/17 graceful-shutdown integration tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(graceful-shutdown): extract DrainTriggerExecutor

ElsaShellDrainHandler (CShells IDrainHandler) and
DrainOrchestratorHostedService (.NET IHostedService.StopAsync) inlined
near-identical try/catch/log shapes around IDrainOrchestrator.DrainAsync:

  - call DrainAsync(<trigger>, ct)
  - branch on outcome: DeadlineExceeded/AbortedByUnhandledException →
    Warning, otherwise Information
  - catch InvalidOperationException (parallel-drain rejected by the
    orchestrator) → log Information and swallow

The two had already drifted: host-stop's success log omitted the
paused/waited durations the shell-handler version included, and the
"skipped" message disagreed on the trigger label ("Host-stop drain
skipped" vs "Shell drain skipped"). Centralised the shape in a small
internal static helper so the two — and any future trigger source —
stay uniform.

Both call sites collapse to a single line. Net diff drops 22 lines from
the two consumers and adds a 25-line helper that they both delegate to.
The unified log copy now consistently includes paused/waited durations
on the success path and uses the caller-supplied contextLabel
("Shell drain", "Graceful drain") in all three messages so operators
can attribute log entries by trigger source.

Files:
- src/modules/Elsa.Workflows.Runtime/Services/DrainTriggerExecutor.cs (new)
- src/modules/Elsa.Workflows.Runtime/Lifecycle/ElsaShellDrainHandler.cs
- src/modules/Elsa.Workflows.Runtime/HostedServices/DrainOrchestratorHostedService.cs

103/103 runtime unit + 17/17 graceful-shutdown integration tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(workflows-runtime): drop redundant DrainOrchestratorHostedService from CShells path

In CShells deployments, host stop already drives drain via CShellsStartupHostedService → IDrainHandler →
ElsaShellDrainHandler, scoped per shell (FR-027). The additional .AddHostedService<DrainOrchestratorHostedService>()
in ShellFeatures/WorkflowRuntimeFeature was firing a second non-force DrainAsync that the orchestrator rejected
with InvalidOperationException — silently swallowed by DrainTriggerExecutor, but logged on every host stop and
semantically muddled (IHostedService is host-level, not per-shell).

Keep the registration on the IModule path (Features/WorkflowRuntimeFeature) where there is no shell platform
and host-stop is the only available drain trigger. Update ElsaShellDrainHandler XML docs to reflect the now-clean
single-trigger model in CShells.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime): always dispose ExecutionCycleHandle in tracking middleware

Previously the success path relied on ExecutionCycleAwareCommitStateHandler to dispose the handle after the
runner's commit completed. If a custom dispatcher or test double exited the pipeline without invoking commit
(by design or by accident), the handle stayed registered, IExecutionCycleRegistry.ActiveCount never reached
zero, and drain spun in WaitForExecutionCyclesAsync until the deadline fired — incorrectly force-cancelling
instances that had already finished cleanly.

Collapse the existing try/catch(rethrow) into try/finally so the middleware itself disposes the handle for
both exception and commit-elided paths. Disposal remains idempotent via the ExecutionCycleHandle._disposed
Interlocked guard, so the normal-path dispose by ExecutionCycleAwareCommitStateHandler is a harmless no-op.

Adds an integration regression test that drives the middleware with a stub Next that returns without invoking
commit and asserts ActiveCount returns to zero.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime): serialize QuiescenceSignal pause-state persistence

Both PauseAsync and ResumeAsync used to release the inner lock before issuing the persistence I/O. A rapid
Pause → Resume sequence could leave the persisted state inconsistent: PauseAsync's slow SaveAsync could land
AFTER ResumeAsync's DeleteAsync, leaving the key present in the store while in-memory state was None. On host
restart, InitializePersistedStateAsync would find the stale key and start the runtime in the paused state
the operator had already cancelled.

Introduce a dedicated SemaphoreSlim that serializes persistence I/O, with each I/O re-reading the live
in-memory state inside the semaphore. N racing Pause/Resume calls now produce N serialized writes, each
reflecting the most recent in-memory transition — so the final persisted state always matches final
in-memory state.

Adds a regression test that gates SaveAsync, races a Resume behind it, and asserts the store is empty after
both complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(workflows-runtime): trim verbose comment in ExecutionCycleTrackingMiddleware finally block

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(workflows-runtime): use 'using var' for ExecutionCycleHandle in tracking middleware

Replace the explicit try/finally that only existed to call handle.Dispose() with a `using var` declaration —
identical semantics (compiler-emitted finally with idempotent dispose), more idiomatic. The regression test
HandleReleasedWhenCommitIsElided continues to validate the leak-free property.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime,api): proper 409 conflict shape + shell-scoped pause-persistence key

ForceDrain endpoint: the 409 path returned `new ForceDrainResponse()` whose `Outcome` was null at runtime
despite the `= null!` annotation, so any strongly-typed client deserializing the conflict body and reading
`Outcome.OverallResult` got an NRE. Switch to the existing `ConflictResponse` shape with
`Code = "DrainInProgress"` and the current runtime status. Routed via HttpContext.Response.WriteAsJsonAsync
because Send.ResponseAsync is constrained to the endpoint's TResponse and cannot send a sibling DTO.

QuiescenceSignal persistence key: the DI-registered `IQuiescenceSignal` was constructed with
`shellName = null` (DI doesn't inject `string?` defaults), so every shell shared the key
`elsa.quiescence.pause.default`. In a CShells multi-shell deployment under
PausePersistencePolicy.AcrossReactivations this caused cross-shell contamination — pausing shell A would
re-pause shell B on its next activation. Replace the simple AddSingleton<IQuiescenceSignal,...> registration
in ShellFeatures/WorkflowRuntimeFeature with a factory that injects `CShells.ShellSettings` and forwards
`Settings.Id` as the shell name. The IModule registration is unchanged (no shell platform; null shellName
remains correct there).

Adds a unit regression test that two QuiescenceSignal instances with different shellNames write to disjoint
persistence keys and never to the legacy "default" key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(quiescence): use TryGetValue for ContainsKey+indexer assertions

Combines existence check and value retrieval into a single dictionary lookup, addressing the code-quality
bot's repeated suggestion. No behavior change — both PauseWritesKey and PersistenceKeyIncludesShellName
still assert the same keys exist with the same content.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update specs/002-graceful-shutdown/contracts/admin-endpoints.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix(workflows-runtime): decouple QuiescenceSignal persistence from caller cancellation

PersistAsync used to forward the caller's CancellationToken to both _persistenceMutex.WaitAsync and the
store I/O. If an HTTP request was cancelled between the in-memory transition (already committed under
_sync) and the persistence call, the I/O was silently skipped — leaving AdministrativePause set in memory
with no persisted record. The idempotent fast-path on subsequent PauseAsync calls (transitioned == false)
meant no retry would happen, so on host restart InitializePersistedStateAsync would find no key and the
runtime would come back unpaused, defeating PausePersistencePolicy.AcrossReactivations.

Drop the parameter from PersistAsync entirely; use CancellationToken.None for both the semaphore wait and
the store I/O. The in-memory transition is already committed by the time PersistAsync runs, so persistence
must complete to keep the store consistent with memory. The public PauseAsync/ResumeAsync methods still
accept a CancellationToken (interface contract) — it just no longer reaches the persistence layer.

Adds a regression test that calls PauseAsync with a pre-cancelled token and asserts both in-memory pause
and the persisted key land correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime,api,docs): apply Copilot review feedback batch

Code:
- DrainOrchestrator.TryForceStopAsync now bounds force-stop with the *remaining* drain budget
  (deadlineAt - now), not the full overall TimeSpan. A per-source pause that already burned the
  shutdown window can no longer get another full deadline's worth of force-stop runway.
- DrainOrchestrator catch filter narrowed: drop `ex is not InvalidOperationException` exclusion.
  The "drain already in progress / completed" IOEs are thrown outside the protocol's try block,
  so they bubble out without entering this handler. Any IOE that lands here is incidental
  (e.g., from a store inside the drain) and should now be captured into the outcome rather
  than escaping the whole drain.
- ResumeEndpoint 409 path now returns the discriminated ConflictResponse shape (matching
  ForceDrain) instead of a plain StatusResponse. Routed via HttpContext.Response.WriteAsJsonAsync
  because Send.ResponseAsync is constrained to TResponse.
- Conflict codes aligned to kebab-case across both endpoints to match the contract spec
  (`runtime-draining` and `drain-in-progress`).

Spelling sweep — American English per constitution v1.0.1 III:
- DrainOrchestrator.cs: "serialised" → "serialized"
- WorkflowInterruptedPayload.cs: "serialised" / "deserialise" → "serialized" / "deserialize"
- PassiveIngressSource.cs: "behaviour" → "behavior"
- DeadlineBreachEndToEndTests.cs: "serialisable" → "serializable"
- specs/002-graceful-shutdown/quickstart.md: "behaviour" → "behavior"
- specs/002-graceful-shutdown/checklists/requirements.md: "behaviour" → "behavior"

Doc/contract alignment:
- quickstart.md: force route corrected from /force to /force-drain.
- quiescence-signal.md: removed StateChanged event from contract (interface doesn't define it);
  corrected persistence section to describe InitializePersistedStateAsync via shell initializer
  / startup task rather than constructor read; added the per-shell key discriminator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime): correct DI lifetimes for ExecutionCycleTrackingMiddleware and WorkflowRuntimeAdminService

Two strict-DI-validation failures surfaced in tests using BuildServiceProvider with validate-on-build:

1. ExecutionCycleTrackingMiddleware was registered as AddSingleton<>, but its constructor takes
   WorkflowMiddlewareDelegate next — supplied by the workflow execution pipeline builder via
   UseMiddleware<>(), not from DI. The registration was both unused (no consumer resolves it through
   the container) and broken (DI fails to construct it because next is unregistered). Removing both
   registrations.

2. IWorkflowRuntimeAdminService was registered as AddSingleton<> but depends on the scoped
   INotificationSender (mediator) — captive-dependency violation. All consumers (Pause/Resume/
   Status/ForceDrain endpoints) are FastEndpoints, which are scoped per request, so AddScoped is
   the correct alignment. The other deps (IQuiescenceSignal / IIngressSourceRegistry /
   IDrainOrchestrator / ISystemClock) are singletons and resolve fine from a scoped consumer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflows-runtime): restore commit-handler-only success disposal + true Cancel idempotency

Two issues raised by Copilot's latest review on commit 32a9c0519:

1. ExecutionCycleTrackingMiddleware was disposing the handle at the end of InvokeAsync (via `using var`),
   but WorkflowRunner runs commit AFTER the pipeline returns (WorkflowRunner.cs:235). That meant the handle
   was disposed BEFORE the runner's terminal commit, and the drain orchestrator's
   `await handle.Disposed` would unblock too early — reintroducing the runner-clobber race the original
   design protected against (see ExecutionCycleAwareCommitStateHandler XML doc).

   Revert to the original shape: only dispose on exception path. ExecutionCycleAwareCommitStateHandler
   remains the SOLE success-path disposer, running in its finally block AFTER the inner commit lands.
   The earlier "leak when commit is elided" concern was a non-issue in production (the standard runner
   always commits); the buggy `HandleReleasedWhenCommitIsElided` test that specified the wrong contract
   is removed. The existing `ActiveCountReturnsToZero` test (which uses the real runner end-to-end)
   already verifies success-path disposal.

2. ExecutionCycleHandle.Cancel() was documented as idempotent but only short-circuited via the
   _disposed flag. Repeated Cancel() calls before Dispose could trigger the cancel callback multiple
   times — easy to accidentally fire non-idempotent cancellation side effects more than once. Add an
   Interlocked _cancelled guard so callback + CTS cancellation run at most once. Existing test that
   documented the leaky behavior is updated to assert the now-truly-idempotent contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update logging levels and remove unused features in appsettings files

* refactor(workflows-runtime): improve graceful shutdown options handling and cleanup solution

Refactor the handling of `GracefulShutdownOptions` to ensure options are applied correctly without directly invoking the delegate. Update DI registrations to use appropriate lifetimes and remove redundant wrapper services. Additionally, clean up the solution by removing unused projects and documentation folders.

* feat(identity, workflows-runtime): add validation for identity and graceful shutdown options

Introduce validation capabilities for `IdentityTokenOptions` and `GracefulShutdownOptions`. Implement extension methods for option validation, enhance service registration, and add unit tests to ensure configurations are validated at startup. Update solution to include new unit test projects.

* update(docs): clarify shutdown log message expectations and levels in quickstart.md

Optimize explanation of expected log message sequence during graceful shutdown and specify logging levels.

* docs: amend constitution to v1.1.0 (SRP, DRY, KISS, conciseness under Principle VII)

* refactor(multitenancy): rename and restructure TenantTaskManager to TenantTaskLifecycleCoordinator

Rename `TenantTaskManager` to `TenantTaskLifecycleCoordinator` and relocate to a new directory structure, enhancing code organization and test consistency. Retain functional behaviors with no logic alterations. Update unit tests to reflect the naming changes, ensuring consistency with the refactored code structure.

* Update logging levels and dependencies

- Set default logging level to Debug in appsettings.Development.json
- Add missing using directives for Elsa workflows management and runtime features
- Update CShells package versions to 0.0.18-preview.104

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-05-02 19:27:08 +02:00
Heku c372e5aff4
Code cleanup (#7395)
* refactor: replace obsolete API usage

* refactor: remove unnecessary string interpolation
2026-04-15 14:03:42 +02:00
Sipke Schoorstra 0ef0135303
Merge remote-tracking branch 'origin/patch/3.5.3' into develop/3.6.0 2025-12-10 20:48:50 +01:00
Sipke Schoorstra 2f135f3e61
Add service registration for BookmarkQueueWorker. 2025-11-12 22:55:22 +01:00
Sipke Schoorstra b9360d3b5f
Add missing service registration for WorkflowResumer. 2025-11-12 17:18:38 +01:00
Sipke Schoorstra 2c0b3da5de
Addresses warnings and enforces null safety (#7051)
* Enhance null-safety annotations across modules and refactor for improved consistency:

- Added `null!` annotations to enforce non-nullability expectations.
- Updated workflows, tests, and runtime services to handle default null values reliably.
- Removed obsolete and unused APIs, simplifying interfaces and improving maintainability.
- Refactored methods and properties for clarity, thread-safety, and consistency.
- Adjusted test configurations for code coverage tracking and integration improvements.

* Refactor activity iteration in container serialization tests to simplify type casting.
2025-11-12 16:56:31 +01:00
Sipke Schoorstra 490c8a2c9e
Addresses warnings and enforces null safety (#7050)
* Simplify test setup by removing `Input` wrapper and fix trimming warnings with `UnconditionalSuppressMessage` annotations.

* Add trimming warning suppression to `ArgumentJsonConverter` with `UnconditionalSuppressMessage`

- Annotated `Read` method to suppress `IL2055` warning caused by dynamic type resolution.
- Provided justification reflecting dynamic type registration in the well-known type registry.

* Add root namespace to project file and suppress EF Core usage warning

- Added `RootNamespace` property to `Elsa.Persistence.EFCore.Common.csproj` for consistency.
- Annotated `DbSchemaAwareMigrationAssembly` with `SuppressMessage` to suppress EF1001 usage warning and provide justification.

* Suppress obsolete API warnings in workflow runtime projects

- Added `#pragma warning disable CS0618` to suppress obsolete member warnings in `ObsoleteWorkflowRuntime.cs`, `LocalWorkflowRuntime.Obsolete.cs`, and `DistributedWorkflowRuntime.Obsolete.cs`.
- Updated `Directory.Build.props` to globally suppress `CS0618` for backward compatibility during migration.

* Annotate properties with non-nullable default initializers across modules to enforce null safety.

* Add `Priority` and `Deprecated` properties to `StorageDriverDescriptor` model

* Update src/modules/Elsa.Workflows.Runtime.Distributed/Services/DistributedWorkflowRuntime.Obsolete.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/Elsa.Workflows.Runtime/Services/ObsoleteWorkflowRuntime.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update src/modules/Elsa.Workflows.Runtime/Services/LocalWorkflowRuntime.Obsolete.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Clean up XML comments and improve consistency across modules.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-12 15:53:23 +01:00
bobhauser f37d368cc6
Simplify registration of IWorkflowResumer (#6983)
Co-authored-by: Bob Hauser <rhauser@kinaxis.com>
2025-11-11 19:07:01 +01:00
Sipke Schoorstra 72ad243ed4
Merge 3.5.1 into 3.6.0 (#6907)
* Introduce `IWorkflowResumer` and `ActivityInputEvaluatorContext`, refactor endpoint handling, extend logging, and improve bookmark queue processing.

* Remove deprecated WorkflowContexts module and optimize project.

Deleted the Elsa.Studio.WorkflowContexts module and references from solution files. Corrected minor errors in remaining code and updated project configurations to align with the new structure.```

* Update GitHub workflows to track `develop/3.6.0` branch instead of `patch/3.5.1`.

* Fix inconsistent formatting in `InputDescriptor` constructor and properties.

* Add XML documentation for `DictionaryValueEvaluator` in `UIHints/Dictionary` module

* Refactor `DictionaryValueEvaluator` to improve readability and simplify dictionary evaluation logic.
2025-09-13 13:05:52 +02:00
Sipke Schoorstra c549f49dfb
Fix race condition when sending same stimuli (#6895)
* Introduce `WorkflowResumer` service and deprecate `BookmarkResumer`.

- Adds `IWorkflowResumer` and its implementation for workflow resumption.
- Marks `BookmarkResumer` and related interfaces as obsolete.
- Refactors dependent services to use `WorkflowResumer`.
- Enhances `ResumeBookmarkRequest` to include `ActivityInstanceId`.
- Updates logging and queue handling logic to align with the new resumption approach.

* Update lock key prefix in `WorkflowResumer` for consistency with service naming.

* Add exception handling for distributed lock acquisition in `WorkflowResumer`

- Wrap distributed lock logic with `try-catch` to handle `TimeoutException`.
- Improve error message when lock acquisition fails due to timeout.
- Preserve existing workflow resumption behavior and logging.

* Update src/modules/Elsa.Workflows.Runtime/Filters/BookmarkFilter.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Optimize `BookmarkFilter` hashing logic for improved performance and readability.

* Merge remote-tracking branch 'origin/enh/locked-bookmark-resumption-2' into enh/locked-bookmark-resumption-2

* Remove unused variable and redundant line breaks for cleaner code.

* Clean up logging configuration by removing unused debug log levels.

* Update src/modules/Elsa.Workflows.Runtime/Services/WorkflowResumer.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Handle collections in `BookmarkFilter` hashing to ensure determinism and improve compatibility.

* Refactor `BookmarkFilter` hashing logic for clarity and consistency.

* Improve `TimeoutException` handling with a more descriptive message in `WorkflowResumer`.

* Update src/modules/Elsa.Workflows.Runtime/Filters/BookmarkFilter.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Simplify `BookmarkFilter` by utilizing `using` directives and refining type references.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-11 22:30:25 +02:00
Sipke Schoorstra 4b3b39f74e
Refactor activity execution record capturing (#6836)
Replaced `CaptureActivityExecutionRecordMiddleware` with a notification-based approach using `ActivityCompleted` and `CaptureActivityExecutionState`. Removed obsolete middleware setup and extensions for better maintainability.
2025-08-04 08:44:42 +02:00
Sipke Schoorstra 6d38ebbc97
Merge remote-tracking branch 'origin/bug/activity-execution-record-state' into develop/3.6.0 2025-08-01 22:55:09 +02:00
Sipke Schoorstra 8e347a8ae6
Refactor activity execution record capturing
Replaced `CaptureActivityExecutionRecordMiddleware` with a notification-based approach using `ActivityCompleted` and `CaptureActivityExecutionState`. Removed obsolete middleware setup and extensions for better maintainability.
2025-08-01 20:53:48 +02:00
jeanbaptistedalle c9bdcd5a84
Create trigger payload validation, refacto HttpEndpoint validator and create Cron validator (#6641) 2025-05-20 19:52:43 +02:00
Sipke Schoorstra c8ed08cc85
Remove obsolete properties and refactor activity evaluation (#6603)
* Remove obsolete properties and refactor activity evaluation

Refactored activity input and log persistence property evaluation using improved notification handlers. Removed redundant `ActivityState` property and associated serialization logic, ensuring payloads are only serialized when necessary. All changes streamline workflow processing and enhance maintainability.

* Refactor mediator call to inline cancellation token.

Replaced the separate variable for the cancellation token with an inline reference for clarity and reduced redundancy. This simplifies the code without altering functionality.
2025-04-18 16:21:25 +02:00
Sipke Schoorstra b88d12cdd8
Fixed Log Persistence Mode Evaluation For Activity Execution (#6595)
* Refactor log persistence mode evaluation for activity execution

Updated functionality to evaluate and filter log persistence modes during activity execution. Added middleware, interfaces, and supporting methods to manage log configuration, ensuring only persistable inputs and outputs are retained in execution mapping. Updated pipeline to include the new middleware.

* Refactor log persistence mapping and evaluation logic

Updated log persistence evaluation to use separate input/output maps, ensuring a more modular and maintainable structure. Adjusted property key handling and introduced a dedicated helper method for evaluating persistence properties. Added middleware for log persistence mode evaluation to the workflow execution pipeline.

* Refactor log persistence logic and restructure namespaces.

Centralizes log persistence logic under a dedicated `LogPersistence` namespace. Simplifies interfaces and methods to streamline functionality, ensuring clarity and consistency in log persistence evaluations.

* Refactor log persistence methods for encapsulation.

Converted multiple public methods to private to enhance encapsulation and adherence to the principle of least privilege. Introduced a helper method `ResolveFinalLogPersistenceMode` to improve code clarity and maintainability.

* Refactor log persistence with improved type safety and structure

Updated methods and properties related to log persistence to remove nullable types, enhance clarity, and ensure type safety. Simplified configurations and refactored logic for evaluating persistence modes, reducing redundancy and improving maintainability.

* Add XML documentation to IActivityPropertyLogPersistenceEvaluator

This commit introduces XML comments to provide clarity on the purpose and functionality of the interface and its methods, aiding developers in understanding their usage and behavior during workflow execution.

* Refine log persistence logic in activity execution mapping.

Ensure that log persistence modes are correctly handled by adding explicit checks for `LogPersistenceMode.Inherit`. This prevents potential ambiguities and ensures accurate property mapping during workflow execution.

* Refactor state handling and log persistence evaluation.

Updated method signatures for stricter type consistency and improved readability. Introduced additional resolution step in log persistence to handle legacy configurations more effectively. This enhances code maintainability and alignment with expected behavior.

* Update src/modules/Elsa.Workflows.Core/Extensions/ActivityExtensions.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-17 18:03:06 +02:00
Sipke Schoorstra f7743a0fe6
Fix race condition in Distributed Workflow Runtime during same-workflow event publishing (#6538)
* Add asynchronous stimulus dispatching to workflow runtime

Introduced the BackgroundStimulusDispatcher and related components to enable asynchronous stimulus dispatching. Updated event publishing logic to support both synchronous and asynchronous delivery. These changes improve extensibility and allow better performance for handling workflow stimuli.

* Update event publishing to include isAsync parameter

Added a boolean parameter to differentiate between asynchronous and synchronous event publishing. Ensured correct value is passed based on workflow execution mode, improving clarity and functionality. Removed outdated TODO comment.

* Fix default value for Asynchronous and add activity type helper

Set the default value of the Asynchronous input property to `true` in `PublishEvent`. Additionally, utilize `ActivityTypeNameHelper` in `EventPublisher` to generate activity type names for improved consistency and clarity.

* Remove unused import from EventPublisher.cs

Eliminated the unnecessary import of Elsa.Workflows.Runtime.Requests. This cleanup helps reduce code clutter and improves maintainability.

* Set default value for Asynchronous property and update Payload.

Added a default value of `true` for the `Asynchronous` property to ensure consistency in event delivery behavior. Also, removed the unnecessary default value from the `Payload` property description for clarity.

* Simplify XML doc comment in IStimulusDispatcher interface

Refined the XML documentation for the `SendAsync` method by shortening the description and clarifying the statement. This improves readability and maintains the intent of the comment.

* Add MassTransit stimulus dispatching functionality

Introduced `DispatchStimulusRequestConsumer` and associated consumer definitions to enable stimulus dispatching. Added `MassTransitStimulusDispatcher` service and related options for configuring concurrency and endpoint behavior. Updated `MassTransitWorkflowDispatcherFeature` to register the stimulus dispatcher and allow enhanced dispatch configuration.

* Refactor stimulus dispatching to use a serialized message.

Introduced `DispatchStimulus` to encapsulate serialized requests. Updated dispatch logic to utilize `IPayloadSerializer` for serialization and deserialization, enabling message transport in a lightweight format.

* Remove Asynchronous input property from PublishEvent activity

The Asynchronous input property was removed as it was unnecessary, with a hardcoded `true` value now passed directly to the event publisher. This simplifies the code and ensures consistency in how events are published.

* Remove ProtoStringExtensions and consolidate string utilities.

Moved `EmptyIfNull` and `NullIfEmpty` methods to the existing `StringExtensions` class in `Elsa.Workflows.Core` for centralization. Updated references to use the consolidated extension methods. Deleted `ProtoStringExtensions` as it is now redundant.

* Add missing imports for Elsa.Extensions across mappers

Added `using Elsa.Extensions` to multiple mapper files in the runtime module. This ensures consistent access to shared extension methods, improving code clarity and reducing potential errors.

* Add missing Elsa.Extensions namespace to WorkflowInstance

The `using Elsa.Extensions` directive was added to ensure access to required extensions. This resolves potential issues with missing dependencies or functionality in the `WorkflowInstance` class.
2025-03-31 18:11:27 +02:00
Marius Vasile Vușcan 1ea83aff14
Removed optional purge 2025-03-12 13:58:38 +02:00
Marius Vasile Vușcan c2161d057a
Added missing functionalities from main as part of the blueberry merge 2025-03-12 13:34:57 +02:00
Marius Vasile Vușcan c4048fad4d
Merge branch 'refs/heads/main' into blueberry
# Conflicts:
#	.github/workflows/packages.yml
#	Directory.Packages.props
#	samples/aspnet/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql/Elsa.Samples.AspNet.EntityFrameworkCore.PostgresSql.csproj
#	src/Directory.Build.props
#	src/apps/Elsa.Server.LoadBalancer/Elsa.Server.LoadBalancer.csproj
#	src/apps/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
#	src/apps/Elsa.Studio.Web/Elsa.Studio.Web.csproj
#	src/apps/ElsaStudioWebAssembly/ElsaStudioWebAssembly.csproj
#	src/bundles/Elsa.Server.Web/Elsa.Server.Web.csproj
#	src/clients/Elsa.Api.Client/Elsa.Api.Client.csproj
#	src/clients/Elsa.Api.Client/Extensions/DependencyInjectionExtensions.cs
#	src/clients/Elsa.Api.Client/Resources/Alterations/Models/AlterationPlan.cs
#	src/clients/Elsa.Api.Client/Resources/Alterations/Models/AlterationPlanParams.cs
#	src/clients/Elsa.Api.Client/Resources/Alterations/Models/AlterationWorkflowInstanceFilter.cs
#	src/clients/Elsa.Api.Client/Resources/Alterations/Responses/RunRequest.cs
#	src/modules/Elsa.Common/Elsa.Common.csproj
#	src/modules/Elsa.Dapper/Elsa.Dapper.csproj
#	src/modules/Elsa.Expressions/Elsa.Expressions.csproj
#	src/modules/Elsa.Http/Activities/SendHttpRequestBase.cs
#	src/modules/Elsa.Http/Elsa.Http.csproj
#	src/modules/Elsa.MassTransit.AzureServiceBus/Handlers/RemoveOrphanedSubscriptions.cs
#	src/modules/Elsa.MassTransit/Services/MassTransitWorkflowDispatcher.cs
#	src/modules/Elsa.ProtoActor/Mappers/WorkflowExecutionResultMapper.cs
#	src/modules/Elsa.ProtoActor/Proto/Shared.proto
#	src/modules/Elsa.ProtoActor/Proto/WorkflowInstance.Messages.proto
#	src/modules/Elsa.Quartz.EntityFrameworkCore.PostgreSql/Elsa.Quartz.EntityFrameworkCore.PostgreSql.csproj
#	src/modules/Elsa.Quartz/Elsa.Quartz.csproj
#	src/modules/Elsa.Workflows.Core/Contexts/StorageDriverContext.cs
#	src/modules/Elsa.Workflows.Runtime.ProtoActor/Extensions/ProtoOutputExtensions.cs
#	src/modules/Elsa.Workflows.Runtime/Activities/ExecuteWorkflow.cs
#	src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs
#	src/modules/Elsa.Workflows.Runtime/Handlers/ResumeExecuteWorkflowActivity.cs
#	src/modules/Elsa.Workflows.Runtime/HostedServices/WorkflowInboxCleanupHostedService.cs
#	src/modules/Elsa.Workflows.Runtime/Services/DefaultWorkflowRuntime.cs
#	test/component/Elsa.Workflows.ComponentTests/Scenarios/ExecuteWorkflows/ExecuteWorkflowsTests.cs
#	test/component/Elsa.Workflows.ComponentTests/Scenarios/ExecuteWorkflows/Workflows/MainWorkflow.cs
#	test/component/Elsa.Workflows.ComponentTests/Scenarios/ExecuteWorkflows/Workflows/SubroutineWorkflow.cs
#	test/integration/Elsa.Workflows.IntegrationTests/Scenarios/WorkflowCancellation/ProtoActorTests.cs
2025-03-10 15:13:26 +02:00
Sipke Schoorstra dd92fa097c
Add migration files for database schema V3.4
This commit introduces migration files for multiple database providers (MySQL, SQL Server, PostgreSQL, SQLite, and Oracle) to support schema changes for version 3.4. The migrations primarily involve mapping entity schemas, indexes, and table structures for consistency across all supported database systems.
2025-02-22 20:48:56 +01:00
Sipke Schoorstra 0a21b5201a
Add workflow restart functionality for handling interruptions
Introduced a mechanism to identify and restart interrupted workflows. This includes a new `IWorkflowRestarter` contract, its default implementation, and a recurring task for handling restarts. Additionally, updated configurations and added extensions to improve workflow instance filtering and liveness tracking.
2025-02-22 15:10:52 +01:00
Sipke Schoorstra d7900efb31
Enable configurable toggle for workflow inbox cleanup job
Introduced an `IsEnabled` property in `WorkflowInboxCleanupOptions` to allow enabling or disabling the cleanup service. Updated related logic to respect this configuration, removing the redundant `_enableWorkflowInboxCleanupJob` field. Ensures easier management of the inbox cleanup feature via configuration.
2025-02-20 21:25:03 +01:00
Sipke Schoorstra 0065811354 Add toggle for WorkflowInboxCleanupJob in WorkflowRuntimeFeature
Introduced methods to enable or disable the WorkflowInboxCleanupJob. Updated service configuration logic to conditionally register WorkflowInboxCleanupHostedService based on the toggle. This adds flexibility to control cleanup job behavior programmatically.
2025-02-17 19:04:10 +01:00
Sipke Schoorstra 8bc6fa6a57 Refactor activity context management and state handling.
Replaced `ActivityExecutionRecordExtractor` with a `ChangeTrackingDictionary` for better state mutation tracking in activity execution contexts. Introduced tainting mechanisms to track dirty states and ensure precise logging and persistence of activity execution logs. Updated several components like `ActivityExecutionLogSink` and `ExpressionExecutionContext` to utilize these changes effectively.
2025-01-28 20:24:53 +01:00
Sipke Schoorstra 6b288e1990
Update SetCommitStateBehavior method for fluent convenience 2025-01-27 21:13:49 +01:00
Sipke Schoorstra 5e2644f751 Refactor workflow runtime structure and update handlers.
Moved `CancelWorkflowsCommandHandler` to the shared runtime module. Updated related project references, features, and configurations accordingly. Improved `WorkflowInstance` actor to save state using `IWorkflowInstanceManager`.
2025-01-02 11:43:21 +01:00
Sipke Schoorstra 8f8f8579a4 Add support for waiting for child workflows in ExecuteWorkflow
This update introduces the ability to optionally wait for child workflows to complete before finishing the ExecuteWorkflow activity. A bookmark mechanism is used to resume the activity when the child workflow completes. Additionally, a new handler was added to manage the resumption of these workflows upon completion events.
2024-12-18 15:05:46 +01:00
Sipke Schoorstra a2448523a9
Fix race condition and add rate limiting to bookmark queue processing (#6187)
* Fix race condition and add rate limiting to bookmark queue processing

Introduce rate-limited function invocation for bookmark queue processing using ThrottleDebounce library to optimize performance. Update related classes and interfaces to support asynchronous and cancellation-aware operations, improving system responsiveness. Adjust logging to provide more detailed information during bookmark queue handling.

* Enable workflows on bug branches

This change updates the GitHub Actions workflow configuration to trigger on branches with the 'bug/*' pattern. This allows for automated actions on bug fix branches alongside the main branch, improving development and testing processes.
2024-12-07 17:34:10 +01:00
Sipke Schoorstra 692937d7d7
Enhance Multitenancy with Runtime Tenant Management and Task Handling (#6173)
* Work in progress: Add DefaultTenantService for tenant management

Introduce `DefaultTenantService` and its corresponding interface `ITenantService` to manage tenant operations such as finding, getting, and listing tenants. Update `MultitenantBackgroundService` to utilize `DefaultTenantService` for handling tenant lifecycle events. This enhancement standardizes tenant operations and improves the maintainability of the multitenancy feature.

* WIP

* Add multitenancy event handlers and task interfaces

Implemented new interfaces IBackgroundTaskStarter and ITaskExecutor to manage task lifecycle events efficiently. Introduced new classes such as RunBackgroundTasks, RunStartupTasks, and StartRecurringTasks for handling tenant activation and deactivation events. Modified TaskExecutor to implement these interfaces and adjusted tenant registration logic to invoke these new handlers.

* Refactor multitenancy and task management services.

Remove background and recurring task runners, and integrate tenant activation and deactivation into the multitenancy feature. Enable multitenancy in the server application and create a new service for tenant activation and deactivation. This refactor simplifies the management of tenant-specific tasks and enhances the modularity of the platform.

* Refactor background service to use startup tasks

Replaced hosted service implementation with startup tasks for executing multi-tenant tasks and EF Core migrations. Introduced `PriorityAttribute` to manage task execution order, ensuring migrations run before other services that require database access. This simplifies tenant activation with an ordered task execution and removes redundant classes.

* Refactor MultitenancyFeature service registrations

Reorganized service registrations for better clarity and maintainability. Changed the registration of some services to use factory delegates for retrieving existing services to ensure correct dependencies. This refactor improves the flexibility of the tenant lifecycle event handling.

* Update V3_3 migration files

* Add tenant management endpoints and enhance tenant handling

Implemented tenant management endpoints including Add, Get, List, and Update. Enhanced tenant handling by introducing configuration and store-based providers, and improved error logging for tenant updates. Adjusted various internal functionalities to better support multitenancy features through different persistence providers.

* Implement tenant deletion endpoint and refactor migration setup.

Introduce a new API endpoint to handle tenant deletions while providing appropriate responses based on successful or unsuccessful attempts. Refactor migration handling by replacing startup tasks with hosted services across various modules to streamline the migration execution process.

* Add and integrate ConfigurationJsonConverter

Introduce a `ConfigurationJsonConverter` to handle JSON serialization and deserialization of `IConfiguration` objects. This change centralizes configuration serialization logic, leading to cleaner and more maintainable code. Updated various parts of the codebase to use the new serialization utility, ensuring a consistent approach throughout the application.

* Refactor JSON conversion and update tenant endpoint.

Removed unused workflow references and streamlined JSON handling in `ConfigurationJsonConverter`. Simplified tenant ID handling by removing `IIdentityGenerator` and setting a default value for `UpdatedTenant.Id`.

* Add logging for cancelled recurring tasks

Integrated ILogger to log information when a recurring task is canceled due to an OperationCanceledException. This change enhances troubleshooting by providing clearer insights into task cancellations and their underlying reasons, improving maintainability and observability of the task execution process.

* Disable multitenancy support and adjust default Tenant ID.

Multitenancy is now disabled by setting 'useMultitenancy' to false in the configuration. Additionally, the default Tenant's ID has been changed from null to an empty string to prevent potential null reference issues.

* Remove MultitenantHostedService abstraction file

The MultitenantHostedService.cs file was removed as it is no longer necessary. Its responsibilities have likely been refactored or integrated into another service, indicating a simplification or restructuring of the multitenancy handling in the codebase.

* Rename PriorityAttribute to OrderAttribute for clarity.

This change improves the clarity of the code by renaming PriorityAttribute to OrderAttribute, reflecting its actual purpose. All occurrences of the attribute in the codebase have been updated accordingly to maintain consistency. This makes the intent of the code more understandable for future maintenance and development.

* Fix message key retrieval in ProduceMessage activity

Update the ProduceMessage activity to use GetOrDefault for retrieving the message key. This change ensures that a null key is used if no explicit key is provided or if the key is empty or whitespace, preventing potential errors during message production.

* Refactor multitenancy and scheduling services.

Removed DefaultTenantContextInitializer interface and class, refactored tenant activation/deactivation to use try-catch logging, and updated tenant context handling to use IDisposable for context push. New activities and workflows added in Elsa.Server.Web, and scheduling services enhanced to schedule jobs with explicit job keys and groups. Also, adjusted configurations to enable multitenancy, providing improved maintainability and flexibility.

* Remove Example1 activities and disable multitenancy

Deleted Example1Activity, Example1Workflow, and FirstActivity classes to clean up unused code and simplify the codebase. Disabled multitenancy by setting useMultitenancy to false, likely to streamline configuration and resource utilization.

* Fix and normalize URL path concatenation.

Ensure that the base URLs in both base path providers consistently end with a forward slash. This normalization prevents potential issues with endpoint routing and path concatenation, improving overall URL construction robustness.
2024-12-03 15:07:55 +01:00
Sipke Schoorstra a062847db5
ExecuteWorkflow Activity: Add Wait For Completion option (#6153)
* Add bookmark queue purging and ExecuteWorkflow stimulus

Introduce BookmarkQueuePurgeOptions and ExecuteWorkflowStimulus classes for managing workflow queue purging and stimulus handling. Implement related handler and activity modifications to support waiting for child workflows and purging old bookmark queue entries.

* Update activity reference in XML comments

Corrected the activity reference from DispatchWorkflow to ExecuteWorkflow in XML comments to accurately reflect the functionality. This change ensures the comments are aligned with the actual code behavior.
2024-11-26 20:37:41 +01:00
Sipke Schoorstra f53e024d25
Add Elsa.Kafka Module for Kafka Integration with Message Sending and Receiving Activities (#6108)
* Add Kafka module with integration and example setup

Introduced the Kafka module providing consumer integration and activities into the project. This includes new classes for consumer handling, configuration, and activities. An example setup using Docker Compose is also added to facilitate development and testing.

* Refactor KafkaTransportMessage to inline Timestamp namespace

Simplify the namespace usage for the Timestamp type within the KafkaTransportMessage record. This change eliminates the need for a separate using directive for Timestamp, enhancing code readability and maintainability.

* Add support for handling Kafka transport messages

This commit introduces the capability to handle and trigger workflows based on Kafka transport messages. It adds a new handler, notifications, and updates the message stimulus to include correlating fields. Additionally, the Kafka consumers are now managed more modularly with updated startup tasks and mediator integration.

* Enable Kafka integration and fix Kafka options naming

Added support for Kafka integration in Elsa.Server.Web by setting up Kafka configurations in appsettings.json and updating Program.cs. Also, renamed `ConsumerConfigs` to `ConsumerDefinitions` in Kafka options for clarity.

* Add consumer definition enumeration and dropdown support

Introduced `IConsumerDefinitionEnumerator` for managing consumer definitions across providers and implemented in `ConsumerDefinitionEnumerator` class. Enhanced `KafkaFeature` to register these services and updated the `MessageReceived` activity to use a dropdown UI hint for consuming definitions. Improved `StartConsumersTask` by refactoring consumer definition retrieval logic.

* Add SendMessage activity and refine Kafka messaging

Introduce a new SendMessage activity for Kafka, enabling message publishing to specific topics. Refine KafkaTransportMessage model by removing headers and timestamp fields. Adjust the StimulusSender logic to streamline the bookmark queuing process and fix key-value pairing in dropdown options. Update appsettings for corrected Kafka bootstrap server and topic configurations.

* Add producer and topic management support

Introduced interfaces and implementations for managing producer and topic definitions along with their respective enumerators and list providers. Updated `SendMessage` activity to include producer selection and refactored consumer definition providers for better consistency.

* Refactor Kafka configuration property names

Renamed Kafka configuration properties for better consistency and readability across the codebase. Updated property names from `ProducerDefinitions` to `Producers`, `ConsumerDefinitions` to `Consumers`, and `TopicDefinitions` to `Topics`. Added missing input attribute in `SendMessage.cs` and registered additional handlers in `KafkaFeature.cs`.

* Add custom serializers for Kafka message handling

Introduced `DefaultSerializers` class for custom serialization and deserialization of Kafka messages. Updated `MessageReceived` and `SendMessage` activities to use these custom serializers, and modified `KafkaOptions` to include them.

* Fix ExpandoObject serialization method parameter

Changed the serialization type from `ExpandoObject` to the actual type of the object to ensure proper serialization. This ensures that derived types are correctly handled during the serialization process.

* Add Producer and Consumer workflows for Kafka

Introduced two new workflows: `ProducerWorkflow` and `ConsumerWorkflow` for handling Kafka messages. Updated `DefaultSerializers` to use camelCase property naming and modified `appsettings.json` to include `topic-2` and format entries.

* Add JSON serialization to log output in ConsumerWorkflow

This change enhances the log output by serializing messages to JSON format before writing them. The addition of System.Text.Json ensures that the message content is presented in a structured and standardized format in logs.

* Add correlation strategies and update Kafka features

Implemented HeaderCorrelationStrategy and NullCorrelationStrategy, and updated KafkaFeature to support customizable correlation strategies. Added correlation ID handling to Kafka transport messages and updated config and handlers accordingly.

* Add tenant accessor to ConsumerDefinitionWorkflowContextProvider

Integrated ITenantAccessor to the provider to support tenant-specific context loading. Updated the constructor and LoadAsync method to retrieve the tenant information and use it for context-specific operations.

* Switch to MySQL and disable Kafka

This commit changes the SQL database provider from SQLite to MySQL and disables Kafka use. It also includes necessary adjustments such as adding MySQL handling in configuration and connection setups, updating `docker-compose` to include MySQL services, and referencing MySQL projects in the `.csproj` file.

* Add UI property handlers to multiple features

This commit introduces various UI property handlers across several features such as Python, JavaScript, CSharp, and Workflow features to enhance user interface property handling. It also updates the property UI handler resolution logic to better manage cases where providers are not available. Furthermore, adjustments were made in the server configuration to switch database providers and enable Kafka.

* Refactor property UI handler retrieval logic

Modified the logic to fetch property UI handlers by preloading them into a list and then filtering. This change improves readability and potentially performance by reducing repetitive service provider calls.

* Incremental work on Kafka workers and predicate evaluation

* Merge BookmarkInvoker with BookmarkResumer

* Register IWorkerManager

* Change lifetime scope of WorkerManager to Singleton

* **Introduce topic subscription handling for Kafka workers**

Added `IWorkerTopicSubscriber` interface and its implementation for managing topic subscriptions. Enhanced workers to bind triggers and bookmarks dynamically based on existing data. Updated several classes and methods to support topic-based subscriptions and headers.

* Refactor trigger matching logic.

Extract trigger matching conditions into `IsMatchAsync` method for reuse. This enhances code maintainability and readability by reducing redundancy. The new `GetTopic` helper method isolates the topic retrieval logic.

* Add Name property to MassTransitActivityTypeProvider

This commit inserts the Name property in the returned object within the MassTransitActivityTypeProvider class. It ensures that the typeName is included, providing a clearer definition of the activity type.

* Add handling for deleted bookmarks and refactor bookmark removal

Added a new event handler for `BookmarksDeleted` to ensure removed bookmarks are processed correctly. Refactored the bookmark removal logic into a helper method to reduce code duplication and streamline the workflow.

* Switch to asynchronous bookmark queue processing

Refactored the `TriggerWorkflows` handler to use `IBookmarkQueue` instead of directly invoking the `IBookmarkResumer`. This change aims to improve scalability by queueing bookmark resumption requests, enabling better load distribution and async processing. Added necessary helpers and configuration options to support this functionality.

* Remove unused IBookmarkResumer dependency

Simplify the constructor by removing the unused IBookmarkResumer dependency. This cleanup reduces potential confusion and improves code maintainability without impacting functionality.

* Add support for local message processing

Introduced an `IsLocal` property to `MessageReceivedStimulus` for determining if the message event is local to a specific workflow instance. Updated `BookmarkBinding` and related handler methods to utilize `CorrelationId` for local event matching. Removed unused `CorrelatingFields` from `MessageReceived` activity.

* Add nullability checks to IWorker retrieval methods

Updated `GetWorker` methods to return nullable `IWorker` to handle cases where a worker might not exist. Modified code to include null checks and conditional operations to prevent potential null reference exceptions when accessing worker methods.

* Add filtering based on activity type name for triggers and bookmarks

This commit introduces filtering for triggers and bookmarks based on the `MessageReceived` activity type name. It also adds an option to mark messages as local in the `SendMessage` activity, where local messages are delivered to the current workflow instance only. These changes help enhance the management and targeted delivery of messages within the workflow framework.

* Add new Kafka topics and clean up producers config

New topics "topic-3" and "topic-4" were added to the Kafka settings. Unused topic references were removed from the producers configuration to simplify and improve clarity.

* Add predicate to KafkaConsumerActivity in ConsumerWorkflow

Introduced a predicate to the KafkaConsumerActivity using JavaScript expressions to filter messages based on OrderId. This ensures only relevant messages are processed in the workflow.
2024-11-18 13:42:54 +01:00
AlmightyLks 153397e63c
Fix all broken summary xml docs (#6123)
* Add proper summary tags back

* Apply suggestions from code review

Co-authored-by: Robin Sue <robinsue@live.de>

* 69 more files fixed

---------

Co-authored-by: Robin Sue <robinsue@live.de>
2024-11-18 13:41:27 +01:00
Sipke Schoorstra 4acde73dad
Add bookmark queue purger functionality (#6080)
* Add bookmark queue purger functionality

Introduce a new class `DefaultBookmarkQueuePurger` to purge old bookmark queue items. This includes an interface `IBookmarkQueuePurger` and a recurring task `PurgeBookmarkQueueRecurringTask`, with necessary updates to `IBookmarkQueueStore` implementations and application configuration.

* Update purging logic in DefaultBookmarkQueuePurger

Refactor the purging operation to use a threshold date for clarity. This includes updating log messages and filter creation to enhance readability and maintainability.
2024-10-31 09:09:05 +01:00
Sipke Schoorstra 14b772704d
Add workflow activation and startup services. (#6076)
* Add workflow activation and startup services.

Introduced `IWorkflowActivationStrategyEvaluator` and `DefaultWorkflowStarter` to evaluate and initiate workflows based on defined strategies. Updated existing classes and methods to utilize these services, ensuring workflows comply with activation strategies.

* Refactor CreateClientAsync method usage

Modify the call to CreateClientAsync to include instanceId. This ensures that the workflow client is correctly initialized with the instance ID, improving the accuracy of handling workflow instances.
2024-10-30 22:51:14 +01:00
Sipke Schoorstra 939fb95a97
Add multitenancy support for background tasks (#6059)
* Remove initial migrations

Deleted obsolete initial migration files from multiple databases: MySQL, SQL Server, SQLite, and PostgreSQL. This cleanup helps maintain a streamlined and updated migration history.

* Add Document base class and create tenant-specific indices

Introduced a new abstract `Document` base class to unify common properties. Implemented tenant-specific unique indices across multiple collections by including `TenantId` alongside `Id` to ensure uniqueness within tenant scopes.

* Remove outdated migration files

Deleted various migration files under MySql, PostgreSql, Sqlite, and SqlServer directories. This cleanup removes unnecessary schema definitions and helps to streamline the codebase.

* Refactor workflow identity assignment logic

Streamline workflow identity handling to ensure consistent assignment of Id, DefinitionId, and TenantId values. This change integrates tenant prefix and version suffix cleanly, enhancing clarity and maintainability.

* Enable multitenancy support

Added configuration for a new tenant (tenant-1) in appsettings.json and enabled multitenancy feature in Program.cs. This change allows the application to support multiple tenants, with specific configurations for each.

* Refactor route table update to run as startup task

Replaced `UpdateRouteTableHostedService` with `UpdateRouteTableStartupTask` to ensure route table updates are executed during application startup instead of as a hosted service. Updated configuration in `HttpFeature` and adjusted trigger validation logic in `ValidateWorkflowRequestHandler`.

* Add recurring task scheduling and single-node task support.

Introduce `IntervalExpressionType`, recurring task scheduling classes, and `SingleNodeTaskAttribute`. Update `RecurringTasksRunner` to handle schedules and add single-node task logic to `StartupTasksRunner`. Ensure proper namespace changes and configure sample recurring tasks.

* Refactor recurring tasks scheduling system

Replaced existing scheduling classes with a more modular and granular approach. Introduced new classes and interfaces like `ISchedule`, `CronSchedule`, `IntervalSchedule`, and `RecurringTaskScheduleManager`. Updated related methods and code to comply with the new design.

* Refactor background task management

Removed `ExpiredSecretsHostedService` and refactored it into a recurring task. Introduced `TaskExecutor` for shared task execution logic. Updated and renamed feature classes to better represent their purpose, improving task scheduling and execution management.

* Add BackgroundTask abstract class to Elsa.Common module

This new abstract class implements the IBackgroundTask interface with default methods for executing, starting, and stopping tasks asynchronously. It provides a basic framework for background task management in the Elsa.Common module.

* Switch to CreateAsyncScope in DefaultTenantScopeFactory

Updated the CreateScope method to use CreateAsyncScope instead of CreateScope. This change improves asynchronous handling of service scopes within the DefaultTenantScopeFactory class.

* Add tenant handling and move StartWorkers background task

Introduce ITenantAccessor in Worker class for multitenancy support. Rename and relocate StartWorkers service to BackgroundTask, ensuring smoother workflow initialization. Also, update the configuration to support Azure Service Bus connection string.

* Add tenant support and refactor ProtoActor client

Integrated ITenantAccessor in ProtoActorWorkflowClient class to handle multi-tenancy. Refactored methods in the client to support custom headers and added async disposable pattern in various services for proper resource management. Additionally, enabled Azure Service Bus and updated related documentation.

* Add support for custom headers in ProtoActor grain methods

Introduced a T4 template to generate grain methods with custom headers, enabling the use of tenant ID in requests. Updated `ProtoActorWorkflowClient` to employ these methods, removing redundant code and directly utilizing the client for various workflow operations.

* Add tenant middleware to MassTransit configurations

Introduced multitenancy middleware for MassTransit message handling. Added new message type `OrderReceived` and updated RabbitMQ setup in Elsa Server. Applied middleware to configure tenant data on send, publish, and consume operations.

* Add new product workflow and streamline ID handling

Introduced a new `RequestResponseWorkflow` for handling product requests. Simplified ID handling in `WorkflowBuilder` and `ClrWorkflowsProvider` by defaulting to empty strings and adding a version prefix. Enhanced `HttpWorkflowsMiddleware` to correctly parse full request paths.

* Remove redundant files and update configuration

Deleted unused files `Product.cs` and `RequestResponseWorkflow.cs` to clean up the codebase. Updated `Program.cs` configuration: switched MassTransitBroker to Memory and disabled multitenancy.

* Remove MultitenantRecurringTaskService and update AzureServiceBus

Removed `MultitenantRecurringTaskService` and adjusted related code for Azure Service Bus to work without it. This includes removal of tenant accessor dependency from `Worker` and cleanup of service configuration flags in `Program.cs`.

* Increase signal wait timeout to 10000 milliseconds.

Extended the default timeout for signal awaiting methods from 8000 to 10000 milliseconds. This change ensures more flexible and resilient waiting periods, reducing timeout occurrences in scenarios with longer processing times.

* Refactor scheduling service to be a background task

Renamed `CreateSchedulesHostedService` to `CreateSchedulesBackgroundTask` and refactored it to inherit from `BackgroundTask` instead of `BackgroundService`. Simplified the constructor by injecting the required dependencies directly, eliminating the need for a scoped factory.

* Refactor workflow version suffix formatting

Changed the version suffix format from `:v{version}` to `v{version}` and adjusted the ID concatenation accordingly. This improves consistency and readability of workflow IDs.

* Enable multitenancy support in Quartz scheduler

Added `TenantJobListener` to inject tenant context into jobs. Modified `QuartzWorkflowScheduler` to incorporate tenant IDs into job data maps and adjusted the configuration to acknowledge multitenancy settings.

* Remove ConfigureSchedulerHostedService and TenantJobListener

Consolidated tenant resolution logic into JobExecutionExtensions class. Updated ResumeWorkflowJob and RunWorkflowJob to use the new extension method for tenant retrieval. This simplifies the QuartzSchedulerFeature setup by removing the hosted service configuration.

* Refactor HTTP feature and update route table task

Move 'UpdateRouteTableStartupTask' from 'HostedServices' to 'Tasks' and update dependency injection configurations accordingly. Simplify 'DefaultRouteTableUpdater' by removing unnecessary options and tenant-agnostic settings from filters.

* Disable multitenancy in Program.cs

The useMultitenancy flag has been changed from true to false. This update affects the Elsa.Server.Web application configuration.

* Simplify variable usage in HttpWorkflowsMiddleware

Replaced 'fullPath' variable with 'path' to streamline code. This change enhances readability by reducing redundancy and ensures consistency in variable naming throughout the method.

* Enable multitenancy and refactor tenant handling logic

Enable multitenancy in the application and refactor tenant handling logic to use ITenantFinder and ITenantContextInitializer interfaces. Added header constants, updated middleware to use these interfaces, and moved extension methods to the appropriate namespace.

* Add input validation to user registration form

Implemented checks to ensure all required fields are filled and that input data adheres to format requirements. This change reduces errors and enhances form reliability.

* Remove unused import from TenantPrefixHttpEndpointRoutesProvider

This change cleans up the code by removing an unnecessary import statement. It improves code readability and reduces clutter, making future maintenance easier. The functionality remains unchanged.

* Rename filter scope to "tenantPublish" in Probe method

Updated the Probe method in TenantPublishMiddleware.cs to use "tenantPublish" instead of "tenantSend" for better clarity. Ensures consistency with the method's context and aligns with naming conventions.

* Refactor: Remove extraneous whitespace

Eliminate unnecessary whitespace in ProtoActorWorkflowClient.cs for cleaner code. This change helps maintain consistent formatting and improves readability.

* Refactor DefaultRegistriesPopulator for cleaner initialization

Converted constructor to use read-only fields directly, removing unnecessary instance variables. This change simplifies the code by reducing redundancy and making the constructor cleaner.
2024-10-28 19:38:24 +01:00
Sipke Schoorstra f3961c0af5 Update namespaces and correct merge artefacts 2024-10-11 20:41:49 +02:00
Sipke Schoorstra e1bb6a52d2 Remove unnecessary namespace declarations and using statements
This commit consolidates namespaces by removing redundant declarations and unused using statements across multiple files. This helps to streamline the code and improve readability, reducing potential confusion.
2024-07-24 22:51:06 +02:00
Sipke Schoorstra 19d1da12ec Merge remote-tracking branch 'origin/patch/3.2.x' 2024-07-24 22:33:36 +02:00
raymonddenhaan c413f210a9
Add activity execution log sink (#5833)
* Add activity execution log sink

Introduced an interface `IActivityExecutionLogSink` for storing workflow execution log records and implemented it as `StoreActivityExecutionLogSink`. This centralizes and streamlines the handling of persisting execution logs into the workflow's runtime, thus making the process more modular and maintainable. The `PersistActivityExecutionLogMiddleware` has also been refactored to use this sink, replacing the direct usage of the workflow execution log store.

* Refactor logging interfaces and implementations

Replaced specific logging interfaces and implementations with generic ones. The individual interfaces for workflow and activity execution logging have been replaced with a single ILogRecordExtractor and ILogRecordSink interface. Specific implementations have been adjusted to use these new interfaces. This allows for greater flexibility and reuse of logging code.

* Introduce ILogRecordStore interface

The `ILogRecordStore` interface has been introduced to provide a centralized place for handling log records. Both `IActivityExecutionStore` and `IWorkflowExecutionLogStore` have been updated to inherit from this new interface. As a result of this change, the `SaveManyAsync` methods in these two interfaces have been removed to avoid redundancy.
2024-07-24 22:30:14 +02:00
Sipke Schoorstra 5586151bf1 Remove IWorkflowExecutionContextStore and related classes
Removed the IWorkflowExecutionContextStore interface and its implementations, along with the associated handlers and registrations. This change simplifies the codebase by eliminating unnecessary components and their dependencies.
2024-07-18 18:57:42 +02:00
Sipke Schoorstra 827680b3c4 Merge remote-tracking branch 'origin/patch/3.2.x' 2024-07-18 18:25:49 +02:00
Sipke Schoorstra f448e9520a
Fix reloading logic for workflow definitions (#5781)
* Add reloading logic for workflow definitions

Introduced a new mechanism to handle reloaded workflow definitions. This includes creating a "ReloadedWorkflowDefinition" model, updating the caching logic, and modifying notification handlers to work with the enhanced workflow reloading logic. This ensures workflow definitions are updated and managed correctly when published, retracted, or deleted.

* Improve RefreshActivityRegistry documentation

Updated the XML documentation to clarify that `RefreshActivityRegistry` refreshes the `IActivityRegistry` for `WorkflowDefinitionActivityProvider` whenever workflow definitions are reloaded, instead of when they are published, retracted, or deleted.

* Add 'materializer' to user dictionary

The term 'materializer' has been added to the user dictionary to improve code spelling and naming consistency. This change ensures that 'materializer' is recognized as a correct term in the codebase.

* Organize test files by adding a 'Workflows' directory

Renamed 'http-workflow.json' to indicate it belongs under 'Workflows'. This improves file organization and clarity within the 'WorkflowDefinitionReload' scenario.

* Add TestWorkflowMaterializer and TestWorkflowProvider

Introduce `TestWorkflowMaterializer` for deserializing workflows from `TestWorkflowProvider`. Added integration of these new components in the `ReloadWorkflowTests` and `WorkflowServer`. Also renamed `RemoveReloadWorkflowTests` to `ReloadWorkflowTests`.

* Rename and expand workflow reload tests

Renamed `RemoveReloadWorkflowTests` to `ReloadWorkflowTests` to better reflect its purpose and expanded with additional test cases. Added tests to verify workflow and activity registry updates after source provider changes and workflow reloads.

* Update copy settings for workflow test scenarios

Reorganized and added 'CopyToOutputDirectory' settings for JSON files in workflow test scenarios. Ensured all necessary files are correctly included and copied during output directory builds to maintain test consistency.
2024-07-17 09:51:45 +02:00
Sipke Schoorstra ba2603ebd3
Add Bookmark Queue and Restore Background Activity Execution (#5758)
* Update package versions and add PrivateAssets attributes

Updated multiple package versions to the latest releases and added the `PrivateAssets="All"` attribute to several dependencies to improve project isolation. This ensures that the specified packages will not be propagated as transitive dependencies.

* Fix incorrect serializer and generator references.

Replaced `_payloadSerializer` and `_identityGenerator` with `payloadSerializer` and `identityGenerator` respectively. This resolves potential null reference issues and ensures the correct instances are used during workflow and definition processing.

* Refactor background activity scheduling logic

Moved the state commit outside of the deferred task to ensure workflow state is saved before scheduling activities. This change ensures the workflow instance is updated promptly, preventing potential concurrency issues.

* Add bookmark queue management system

Introduced a comprehensive bookmark queue system to manage and process bookmarks efficiently. This includes entities, stores, filters, processors, and workers for both in-memory and distributed environments. Additionally, added notifications to signal bookmark queue workers and updated related contracts.

* Add state commit handler with various implementations

Introduced ICommitStateHandler for committing workflow state. Provided NoopCommitStateHandler and StoreCommitStateHandler implementations. Updated namespaces and dependencies across the project to incorporate these changes.

* Fix order in CommitAsync method for proper task execution

Reorder `ExecuteDeferredTasksAsync` after `SaveAsync` in `CommitAsync` method to ensure that deferred tasks execute correctly after the state is saved, addressing potential issues with task execution dependencies.

* Remove unused and deprecated middleware and annotations

Deleted unused classes `ExecuteDeferredActivityTasks` and `ScheduleBackgroundActivitiesMiddleware`. Removed unnecessary summary tags and unused usings across multiple files to clean up the codebase.

* Remove unnecessary initial migration files

Deleted initial migration files for alterations, management, and identity contexts. These files are no longer needed and their removal helps keep the repository clean and maintainable.

* Add delay in TriggerBookmarkQueueWorker loop

Introduced a 10-second delay within the while loop of TriggerBookmarkQueueWorker. This change aims to alleviate potential tight loop issues, ensuring better performance and resource management.

* Enable all database providers in migration script

Uncomment the providers array and add previously commented database providers (SqlServer, Sqlite, PostgreSql, Oracle). This ensures compatibility with multiple database systems during the migration process.

* Remove unused Microsoft.Extensions.DependencyInjection import

The import statement for `Microsoft.Extensions.DependencyInjection` was not being utilized and has been removed. This cleanup helps in maintaining cleaner and more readable code without unnecessary imports.

* Add Dapper persistence support for bookmark queue

Introduced a new Dapper-based bookmark queue store and related classes for handling bookmark queue items. Various migrations were added to support the new `BookmarkQueueItems` table with tenant-specific columns. Refactored existing EF Core and in-memory bookmark queue item stores to use a unified interface.

* Add MongoBookmarkQueueStore implementation

Added a MongoDB-based BookmarkQueueStore to handle CRUD operations for bookmark queue items. Updated the workflow runtime persistence feature to include and utilize this new store for managing bookmark queue items.

* Add migration helper for altering columns and update keys

Introduced MigrationHelper to simplify altering DateTime and Boolean columns. Updated keys in KeyValueStore and KeyValueFilter classes to use 'Id' instead of 'Key'. Revised migration scripts to utilize the new helper methods for modifying column types.

* Prevent BookmarkQueueWorker.Stop from cancelling when not running

Previously, the Stop method would always cancel the token source regardless of the worker's state. By checking if the worker is running before cancelling, we avoid unnecessary operations and potential errors related to an already cancelled token source.

* Update database schema and bookmark handling logic

Refactored various database migration scripts to allow nullable `WorkflowInstanceId` fields and added new fields such as `ActivityInstanceId` and `CorrelationId`. Enhanced bookmark queue and bound workflow handling logic to support these new fields, ensuring precise and efficient workflow execution and queuing.

* Refactor BookmarkHash to StimulusHash and introduce ActivityTypeName

Renamed BookmarkHash to StimulusHash across multiple components and added ActivityTypeName to enhance traceability. Updated indices, filters, and entities for this change, ensuring consistent naming and improved functionality.

* Remove unnecessary timeouts in AzureServiceBusTests.

Eliminated redundant timeout parameters in _signalManager.WaitAsync calls to streamline test execution and reduce potential waiting time. This change ensures more efficient and accurate testing synchronization.

* Rename and refactor BookmarkQueueWorkerSignaler

Renamed IBookmarkQueueWorkerSignaler to IBookmarkQueueSignaler across the project for clarity. Updated related classes and methods to reflect this change. Added bookmark queue signaling to ensure new items are processed, and renamed BookmarkQueueStore to EFBookmarkQueueStore for consistency.

* Refactor EF Core stores and add migration field

Refactored EF Core store classes to simplify field usage and constructors. Added "CorrelationId" field and created corresponding index in SQLite and PostgreSQL migration files to support new functionality.

* Update workflow context ID and optimize Task handling

Added `ParentInstanceId` to `BulkDispatchWorkflowsStimulus` for context propagation. Also, reset `TaskCompletionSource` in `BookmarkQueueSignaler` to reduce memory usage and ensure proper task lifecycle management.

* Update async method signature and fix variable usage

Modified `AddAsync` to include the `OnSaveAsync` parameter. Corrected the variable used for `parentInstanceId` and utilized `ActivityTypeNameHelper` for generating type names.

* Reset migrations to 3.2

* Generate 3.3 migrations
2024-07-15 22:37:14 +02:00