Commit graph

474 commits

Author SHA1 Message Date
Sipke Schoorstra b4947fbf00
[codex] Harden initial security remediation slice (#7495)
* Harden initial security remediation slice

* Address security review feedback

* Handle null resume request bodies

* Address security review follow-ups

* Address PR review security comments

* Address review comments for zip cache and resume parsing

Agent-Logs-Url: https://github.com/elsa-workflows/elsa-core/sessions/23734885-ebba-4a37-b888-1ded4cc7cff5

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Tighten zip cache path validation

Agent-Logs-Url: https://github.com/elsa-workflows/elsa-core/sessions/23734885-ebba-4a37-b888-1ded4cc7cff5

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Address ZipManager code quality review

* Fix ZipManager test options reference

* Harden cached zip path validation

* Address PR review hardening feedback

* Allow dotted zip download correlation ids

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2026-05-22 00:45:47 +02:00
Sipke Schoorstra e2e00ff235
Add secrets module (#7468)
* Add secrets module

* Address Greptile feedback for secrets module

* Handle unavailable secrets in provider adapter

* Address path combine review comments

* Address additional Greptile secrets review

* Address final Greptile secrets feedback

* Handle secrets test payload failures

* address greptile feedback on secrets rotation

* fix secret recreation concurrency

* address greptile secrets followups

* address greptile secrets reliability feedback

* align secret store capabilities
2026-05-20 11:48:01 +02:00
Sipke Schoorstra 43108c2e48
Add diagnostics console logs (#7462)
* feat: add diagnostics console logs

* test: avoid secret-like redaction fixtures

* fix: address console logs review feedback

* fix: harden console log capture lifecycle

* fix: report console log drop summaries

* fix: address diagnostics review cleanups
2026-05-18 02:16:46 +02:00
Sipke Schoorstra d343b30f76
Add SQLite persistence for structured logs and adjust project references 2026-05-15 09:57:57 +02:00
Sipke Schoorstra 827ad6bc6b
[codex] Add structured log SQLite persistence (#7445)
* Add structured log persistence spec

* Clarify structured log persistence spec

* Plan structured log persistence implementation

* Regenerate structured log persistence tasks

* Address structured log persistence analysis findings

* Add structured log SQLite persistence

* Address structured log persistence review

* Harden structured log write buffer shutdown

* Start structured log SQLite migrations before buffer
2026-05-13 15:57:06 +02:00
Sipke Schoorstra ab3e46bbe2
[codex] Add live server log streaming diagnostics (#7438)
* Add live server logs Spec Kit plan

* Implement live server logs diagnostics module

* Add server log sources and redaction hardening

* Add diagnostics unit tests

* Harden server log hub subscriptions

* Secure server log hub permissions

* Validate server log filter updates

* Add diagnostics logger and source tests

* Add diagnostics integration test project

* Add multi-source diagnostics provider coverage

* Broadcast server log source changes

* Document diagnostics server log streaming

* Add diagnostics sample host wiring

* Record diagnostics validation results

* Address server log PR feedback

* Rename diagnostics module to server logs

* Add server logs shell feature

* Make server logs shell options bindable

* Accept read wildcard for server logs

* Align server logs authorization with API patterns

* Update CShells structure and logging levels, add diagnostics module

* Rename PostgreSql shell feature classes for consistency

* Switch from Sqlite to PostgreSQL for workflow and identity persistence, add QuartzPostgreSql configuration

* Refactor server logs into diagnostics structured logs (#7440)

* Specify diagnostics structured logs refactor

* docs: clarify structured logs spec

* docs: plan diagnostics structured logs

* docs: add diagnostics structured logs tasks

* refactor: rename server logs to diagnostics structured logs

* Refactor PostgreSql persistence features to use centralized entity model handler registration.

* Refactor EFCore persistence features to centralize entity model handler registration for MySql, Sqlite, and Oracle providers.

* Integrate structured logs by renaming server logs, adjusting appsettings, and updating project references.

* Switch from PostgreSQL to Sqlite for workflow and identity persistence, update appsettings configuration.
2026-05-11 00:08:52 +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
Sipke Schoorstra 3decb12680
feat: extend shells integration and modular server support (#7399)
* refactor(deps): use local CShells project refs

Replace CShells NuGet package references with direct project references to the local CShells source to enable developing and testing against local changes and simplify build integration across modules.

* Handle assembly load errors in feature discovery

Added error handling for assembly load failures in feature discovery to improve resilience. Also updated configuration for identity token options and removed unused service bus consumer dependencies. Simplified project structure by moving and cleaning up `Directory.Build.targets` files.

* Refactor configuration and service extension methods.

Moved `ShellSettingsExtensions` and `ShellConfiguration` to `CShells.Abstractions` for better modularity. Added new `ServiceCollectionFeatureExtensions` to improve options registration. Updated appsettings and references to support these changes.

* Introduce ManagementServiceCollectionExtensions to streamline activity and variable registration

Added `ManagementServiceCollectionExtensions` for registering Elsa activity types and variable descriptors, providing a modular and shell-feature-compatible approach to configuration. Updated relevant features to utilize these new extension methods, enhancing code modularity and reducing redundancy.

* Add resilience strategy registration to HTTP feature

Introduced `ResilienceServiceCollectionExtensions` to register resilience strategies within the `Elsa.Resilience.Core` module. Updated `HttpFeature` to incorporate resilience strategies, enhancing HTTP-related resilience configuration leveraging the new extension methods.

* Add new configuration options to JavaScriptFeature

Implemented multiple properties in `JavaScriptFeature` to enhance JavaScript execution: `AllowClrAccess`, `AllowConfigurationAccess`, `ScriptCacheTimeout`, `DisableWrappers`, and `DisableVariableCopying`. These additions enable more flexible and secure configuration of the Jint JavaScript engine.

* refactor(workflows): unify graph caching

Resolve workflow definitions first and store graphs under stable per-version-ID cache keys so different lookup paths share entries.
Centralize cache creation and change-token registration to remove duplicated caching logic.
Skip materializer-unavailable definitions to avoid caching null graphs and simplify flow.

* refactor(tests): centralize default IDs and materializer setup

Introduce constants for default definition and version IDs, and materializer name. Refactor tests to use these constants, streamline graph and definition resolution, and improve cache key creation by sharing logic across tests. Extend tests to check scenarios with unavailable materializers, ensuring caching only occurs for valid cases.

* extend(tests): enhance cache key verification in AutoUpdateTests

Added checks for both workflow definition and version cache keys in AutoUpdateTests to ensure comprehensive cache validation, improving test reliability and coverage.

* refactor(projects): update CShells project paths and solution configuration

Revised project reference paths in `Elsa.ModularServer.Web.csproj` for CShells projects and updated `Elsa.sln` to include new CShells projects, streamlining project organization and build configuration.

* Add `IWorkflowReferenceGraphBuilder` to `WorkflowManagementFeature`; rename `ResilienceShellFeature` to `ResilienceFeature`.

* Refactor `HttpFeature` to use `IMiddlewareShellFeature`, include `HttpWorkflowsMiddleware`, and update `HttpActivityOptions` defaults.

* Add `AddTypeAlias` and `AddVariableTypeAndAlias` extension methods to service collections

- Introduced `AddTypeAlias<T>` method in `ServiceCollectionExtensions.cs` for adding type aliases.
- Added `AddVariableTypeAndAlias<T>` method in `ManagementServiceCollectionExtensions.cs` to add variable types with aliases.

* Remove shell reload API endpoints, orchestrator, and associated tests from the codebase.

* Introduce `DefaultAdminUser` options and refactor `AdminUserInitializer` to use `IOptions`.

* Add user management endpoints: Delete, List, Update with enhanced user store functionality

* Implement `DefaultAdminUser` feature for initial admin bootstrap, decouple `SecurityRoot` from user management endpoints, update related documentation and permissions.

* Add role management endpoints: Delete, List, and Update, including role data models and handle obsolete SecurityRoot policy.

* Update CShells package references to version 0.0.12-preview.66 and refactor `TenantTaskManager` for improved task lifecycle management.

* Replace project references with package references in csproj files and remove unused folders.

* Integrate Nuplane features, add sample packages, and update dependency handling within ModularServer Web.

* Improve `CShells` startup endpoint registration and resolver handling

- Address duplicate endpoint registration by adding state-aware tracking and deduplication
- Resolve `WebRoutingShellResolver` constructor ambiguity by switching to factory-based registration
- Implement a startup-specific filter to prevent redundant endpoint remapping during `ShellsReloaded`
- Update project to use project references for `CShells` and `Nuplane` components in csproj files.

* Update logging configuration in appsettings for Development and Production

- Change default log level to 'Warning' in Development settings
- Adjust Microsoft.Hosting and Elsa.SamplePackage log levels to 'Information'
- Remove Microsoft.EntityFrameworkCore log level entry from Production settings

* Refactor assembly retrieval methods and update endpoint calls for consistency.

* Add `SampleEndpointFeature` and enhance logging and service integration

- Implement `SampleEndpointFeature` with a new endpoint for handling requests.
- Log endpoint access and integrate `ISampleService` with method `DoSomething`.
- Update logging configuration to include `CShells` and `Nuplane` log levels in Development settings.
- Update `Elsa.SamplePackage` to version 1.0.1 and manage dependencies with project and assembly references.
- Modify JSON configuration for `SampleEndpoint`.

* Update package versions for `CShells` to 0.0.13 and `Nuplane` to 0.0.1-preview.15 in props file.

* Refactor `DefaultAdminUserFeature` by renaming `ConfigureServices` to `Apply` and adjusting service registration method.

* Replace project references with package references across multiple projects and remove obsolete cshells-related solution entries.

* Remove `SampleCatalogEndpointExtensions.cs` and related endpoint mappings.

* Improve `TenantTaskManager` by using `TryRemove` for state clean-up and clarify `SemaphoreSlim` disposal behavior.

* Remove hardcoded default admin credentials and add warning for unconfigured AdminRoleName in admin user setup.

* Address unresolved review comments: fix doc comments, security defaults, compilation issue, and restore reload response contracts

Agent-Logs-Url: https://github.com/elsa-workflows/elsa-core/sessions/34eb1e13-833f-4b3c-9db6-2e9221d221b9

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Refine reload endpoints: use specific exceptions, add error messages, rename ReloadedAt to Timestamp, remove unused model

Agent-Logs-Url: https://github.com/elsa-workflows/elsa-core/sessions/34eb1e13-833f-4b3c-9db6-2e9221d221b9

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Potential fix for pull request finding 'Generic catch clause'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Potential fix for pull request finding 'Generic catch clause'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Potential fix for pull request finding 'Generic catch clause'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Add `ExceptionExtensions` with `IsFatal` method and simplify exception handling in `TenantTaskManager`. Remove unused properties from `Directory.Build.props`.

* Add unit tests for `TenantTaskManager` and fix potential state orphaning issue.

* Potential fix for pull request finding 'Generic catch clause'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Fix logger dependency in `SampleEndpointFeature` constructor to use correct type.

* Add unit tests for Elsa Shells API endpoints and update solution configuration.

* Refactor ShellReload models: remove ShellReloadItemResult, update ShellReloadResponse properties.

* Potential fix for pull request finding 'Generic catch clause'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
2026-04-18 14:33:34 +02:00
Sipke Schoorstra f362d44d08
Remove CShells projects from solution file 2026-02-28 21:21:01 +01:00
Sipke Schoorstra 11fec1c85d
Add shell middleware, call‑stack tracking, and workflow reference graph APIs (#7333)
* refactor(deps): use local CShells project refs

Replace CShells NuGet package references with direct project references to the local CShells source to enable developing and testing against local changes and simplify build integration across modules.

* Handle assembly load errors in feature discovery

Added error handling for assembly load failures in feature discovery to improve resilience. Also updated configuration for identity token options and removed unused service bus consumer dependencies. Simplified project structure by moving and cleaning up `Directory.Build.targets` files.

* Refactor configuration and service extension methods.

Moved `ShellSettingsExtensions` and `ShellConfiguration` to `CShells.Abstractions` for better modularity. Added new `ServiceCollectionFeatureExtensions` to improve options registration. Updated appsettings and references to support these changes.

* Introduce ManagementServiceCollectionExtensions to streamline activity and variable registration

Added `ManagementServiceCollectionExtensions` for registering Elsa activity types and variable descriptors, providing a modular and shell-feature-compatible approach to configuration. Updated relevant features to utilize these new extension methods, enhancing code modularity and reducing redundancy.

* Add resilience strategy registration to HTTP feature

Introduced `ResilienceServiceCollectionExtensions` to register resilience strategies within the `Elsa.Resilience.Core` module. Updated `HttpFeature` to incorporate resilience strategies, enhancing HTTP-related resilience configuration leveraging the new extension methods.

* Add new configuration options to JavaScriptFeature

Implemented multiple properties in `JavaScriptFeature` to enhance JavaScript execution: `AllowClrAccess`, `AllowConfigurationAccess`, `ScriptCacheTimeout`, `DisableWrappers`, and `DisableVariableCopying`. These additions enable more flexible and secure configuration of the Jint JavaScript engine.

* refactor(workflows): unify graph caching

Resolve workflow definitions first and store graphs under stable per-version-ID cache keys so different lookup paths share entries.
Centralize cache creation and change-token registration to remove duplicated caching logic.
Skip materializer-unavailable definitions to avoid caching null graphs and simplify flow.

* refactor(tests): centralize default IDs and materializer setup

Introduce constants for default definition and version IDs, and materializer name. Refactor tests to use these constants, streamline graph and definition resolution, and improve cache key creation by sharing logic across tests. Extend tests to check scenarios with unavailable materializers, ensuring caching only occurs for valid cases.

* extend(tests): enhance cache key verification in AutoUpdateTests

Added checks for both workflow definition and version cache keys in AutoUpdateTests to ensure comprehensive cache validation, improving test reliability and coverage.

* refactor(projects): update CShells project paths and solution configuration

Revised project reference paths in `Elsa.ModularServer.Web.csproj` for CShells projects and updated `Elsa.sln` to include new CShells projects, streamlining project organization and build configuration.

* Add `IWorkflowReferenceGraphBuilder` to `WorkflowManagementFeature`; rename `ResilienceShellFeature` to `ResilienceFeature`.

* Refactor `HttpFeature` to use `IMiddlewareShellFeature`, include `HttpWorkflowsMiddleware`, and update `HttpActivityOptions` defaults.

* Add `AddTypeAlias` and `AddVariableTypeAndAlias` extension methods to service collections

- Introduced `AddTypeAlias<T>` method in `ServiceCollectionExtensions.cs` for adding type aliases.
- Added `AddVariableTypeAndAlias<T>` method in `ManagementServiceCollectionExtensions.cs` to add variable types with aliases.

* Update CShells package versions to 0.0.11 and replace ProjectReferences with PackageReferences in project files
2026-02-28 21:16:04 +01:00
Sipke Schoorstra c60e63c3c6
Integrate shells (#7279)
* Add CShells package references and integrate shell features into the application

* Annotate shell features with `[ShellFeature]` attribute and update `TempElsaFeature` to use `ConfigureElsa`.

* Revert "Annotate shell features with `[ShellFeature]` attribute and update `TempElsaFeature` to use `ConfigureElsa`."

This reverts commit e8a875e8f9d14891c5403df50e8ac7e151db25dd.

* Introduce `Elsa.ModularServer.Web` with a minimal API, restructure shell feature configuration, and remove obsolete `CShells` dependency

* Update `CShells` package references, add Fody weaver, and configure new CShells package sources in `NuGet.Config`.

* Adds CShells integration to Elsa

Integrates CShells to enhance modularity and extensibility.

- Adds CShells related projects to the solution.
- Updates NuGet configuration to include CShells preview feed.
- Creates initial app settings for CShells configuration.
- Adds CShells.AspNetCore project reference.
- Implements CShells extensions in the program file.
- Creates shell feature classes in Elsa.Common.
- Creates shell feature classes in Elsa.Expressions.
- Creates shell feature classes in Elsa.Workflows.Core.
- Creates shell feature classes in Elsa.Workflows.Management.
- Creates shell feature classes in Elsa.Workflows.Runtime.
- Creates shell feature classes in Elsa module.

* Refactor CShells: enhance pipeline configuration and features

Consolidated updates to CShells including a new `ResolverPipelineBuilder` for customizable resolver strategy pipelines. Improved assembly scanning, error handling in web routing, and streamlined shell feature dependencies for better clarity and functionality.

* Add feature registration system and FastEndpoints integration

Introduced a feature registration infrastructure with `IInstalledFeatureProvider` and related implementations. Added shell-based feature configurations such as caching, SAS tokens, workflows management, and a FastEndpoints integration module to support dynamic API registration.

* Refactor shell routing and enhance global route handling

Refactored `ShellEndpointRouteBuilder` to simplify initialization and support a combined shell/global route prefix. Enhanced `ShellEndpointRegistrationHandler` to include global route prefix logic and improved feature discovery using pre-resolved descriptors. Updated `Program.cs` for consistent middleware setup.

* Refactor feature endpoints to use `IInstalledFeatureProvider` for improved dependency management and simplified implementation

* Add display names, descriptions, and dependency enhancements to shell features

Standardized `ShellFeature` attributes across `ElsaFeature`, `WorkflowRuntimeFeature`, and `WorkflowManagementFeature` by adding display names, descriptions, and improving dependency declarations. Updated `ElsaFeature` to register `IInstalledFeatureProvider` for feature bridging.

* Add FastEndpoints references and update package versions

Added project references to CShells.FastEndpoints and related projects in multiple csproj files. Updated FastEndpoints package versions in `Directory.Packages.props` for compatibility with .NET 8/9/10. Removed obsolete folder references from Elsa.Caching.csproj and refined the namespace in CShells.AspNetCore.Abstractions.

* Add Identity and DefaultAuthentication features to appsettings.json configuration

* Add project references for Elsa.Identity and CShells.FastEndpoints.Abstractions

* Add `Identity` and `DefaultAuthentication` shell features with enhanced authentication and authorization support

* Set default signing key in `IdentityTokenOptions` for identity configuration

* Add service exclusion infrastructure for shell-specific contexts

Introduce `IShellServiceExclusionProvider` and `IShellServiceExclusionRegistry` to manage excluded service types per-shell. Implement ASP.NET Core-specific providers for authentication and authorization to enable shell-specific configurations. Refactor `DefaultShellHost` to use the new exclusion registry for service inheritance filtering.

* Refactor CShells authentication and authorization APIs

Renamed and unified methods for shell authentication and authorization and added a new combined method `WithAuthenticationAndAuthorization`. Enhanced `AddShells` to automatically register a default configuration provider if none is specified. Updated usage in Elsa.ModularServer to utilize the new API.

* Add Elsa-specific FastEndpoints configurator and feature

Introduce `ElsaFastEndpointsConfigurator` to customize FastEndpoints serialization and value parsing for Elsa workflows. Register this functionality through the new `ElsaFastEndpointsFeature`, which integrates with the shell's dependency injection system using an `IFastEndpointsConfigurator` interface.

* Update Workflow API feature dependency to `ElsaFastEndpoints`

* Pass `cancellationToken` to `ReadToEndAsync` in `PostEndpoint` for improved request handling.

* Add project references for CShells.AspNetCore and CShells.FastEndpoints.Abstractions

* Update CShells package versions to `0.0.6-preview.30` and add `CShells.FastEndpoints.Abstractions`

* Configures shell routing and features

Enables path routing for shells to allow proper routing within each shell.

Configures the ElsaFastEndpoints feature to depend on the FastEndpoints feature.
This ensures that FastEndpoints is properly configured before Elsa's FastEndpoints configurations are applied.

Registers activity types within the WorkflowManagementFeature.
This ensures activities are available for workflow construction and execution.

* Add shell lifecycle management and notification handlers

Introduced interfaces and handlers for shell activation (`IShellActivatedHandler`) and deactivation (`IShellDeactivatingHandler`) to manage shell lifecycles. Added `ShellStartupHostedService` to coordinate shell activation on startup and deactivation on shutdown. Updated notification system to support new shell lifecycle events and renamed existing notification records for consistency.

* Introduces EF Core persistence layer

Adds base classes and implementations for EF Core persistence, including database provider configuration and shell feature integration.

This change introduces a generic approach to configuring EF Core persistence for various Elsa modules, promoting code reuse and simplifying the process of supporting different database providers.

It includes:

- Base classes for database provider configurators and shell features.
- Implementations for Sqlite, SQL Server, MySql, PostgreSql, and Oracle.
- Shell features for Alterations, Identity, Labels, Management (Workflow Definitions and Instances), Runtime, and Tenants modules.

* Add comprehensive feature configuration validation system

Introduce a feature configuration system with support for binding, auto-configuration, and validation using DataAnnotations, FluentValidation, and composite patterns. Includes new validators, binding logic, and extensions to simplify configuration tasks while ensuring robustness and flexibility.

* Add persistence shell features for MySql, Oracle, PostgreSql, and Sqlite

Introduced new shell features to configure MySql, Oracle, PostgreSql, and Sqlite persistence for workflow definitions and runtime data. Updated `appsettings.json` to replace individual Sqlite features with a unified `SqliteWorkflowPersistence`. Made minor code cleanup in `FastEndpointsFeature`.

* Configure shell features for persistence

Added `IServiceCollection` configuration for MySql, Oracle, PostgreSql, and Sqlite shell features to set up persistence services.

* Remove DatabaseProviderConfigurators and refactor persistence shell features

Deleted DatabaseProviderConfigurator classes and restructured persistence shell features by integrating direct configuration logic for MySql, Oracle, PostgreSql, Sqlite, and SqlServer. Simplified configuration by inheriting from abstract shell feature base classes and removed redundant code.

* Correct IWorkflowDefinitionPublisher registration to use WorkflowDefinitionPublisher implementation

* Add resilience feature and scoped services configuration for Sqlite persistence

- Integrated `Microsoft.Extensions.DependencyInjection` to shell features for Sqlite persistence.
- Updated `appsettings.json` and project references to include a new 'Resilience' feature.
- Changed `ICommitStateHandler` service registration in `WorkflowRuntimeFeature` to use an implementation.

* Add `ResilienceShellFeature` for configuring resilience strategies

- Implemented new `ResilienceShellFeature` class to manage services related to resilience features.
- Added scoped and singleton service registrations for resilience strategies, exception detection, and activity invocation.
- Configured expression options for resilience handling in workflows.

* Add new shell features: Alterations, Blob Storage, Caching, Clustering, CSharp, Distributed Runtime, ElsaScript, Flowchart, HTTP, JavaScript, Key-Value, and Labels

* Switch project references to package references for CShells libraries and update to version 0.0.7.

* Potential fix for pull request finding 'Call to 'System.IO.Path.Combine' may silently drop its earlier arguments'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Fix shell feature discovery and remove duplicate service registrations (#7285)

* Initial plan

* Address PR review comments: Add ShellFeature attributes, fix duplicates, and improve security

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Update dependencies and fix scoped services registration in `WorkflowRuntimeFeature`

* Fix null reference and typo in shell feature provider (#7286)

* Initial plan

* Fix null StartupType guard in Find() and typo in variable descriptor

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2026-02-12 20:30:02 +01:00
Sipke Schoorstra cc2e331da4
Merge remote-tracking branch 'origin/release/3.6.0' 2026-02-08 10:52:28 +01:00
Sipke Schoorstra 7bc9035f5e
Implement null TenantId for tenant-agnostic entities (#7226)
* Add ADR for Null Tenant ID, implement tenant-agnostic logic

Introduce ADR-0009 to document the use of `null` for tenant-agnostic entities, enhancing multitenancy handling. Update multitenancy features across the codebase, including EF Core query filters and ActivityRegistry, to handle null as a tenant ID, ensuring tenant-agnostic entities are accessible across all tenants.

* Add multitenancy support in `ActivityTestFixture` by registering `ITenantAccessor`.

* Update src/modules/Elsa.Common/Multitenancy/Implementations/DefaultTenantAccessor.cs

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

* Remove unused `using Elsa.Common.Multitenancy;` from WorkflowDefinitionActivityDescriptorFactory (#7230)

* Initial plan

* Remove unused using Elsa.Common.Multitenancy statement

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Optimize ActivityRegistry.Find to prefer tenant-specific descriptors without performance regression (#7227)

* Initial plan

* Optimize Find(string type) to prefer tenant-specific descriptors with single-pass iteration

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Apply review feedback: combine if statements and add comprehensive unit tests

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Refactor tests for DRYness using theories and helper methods

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Clean up extra whitespace in test file

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Fix default tenant data visibility leak by removing NullIfEmpty conversion (#7229)

* Initial plan

* Remove NullIfEmpty conversion to align with ADR-0008 and ADR-0009

- Updated ElsaDbContextBase to use empty string for default tenant
- Updated ApplyTenantId to stop converting empty string to null
- Updated TenantAwareDbContextFactory to preserve empty string for default tenant
- Updated Store.cs to preserve empty string for default tenant
- This ensures: null = tenant-agnostic (visible to all), "" = default tenant

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Add database migration to convert null TenantId to empty string for SqlServer

- Added Management migration to convert null to "" for WorkflowDefinitions and WorkflowInstances
- Added Runtime migration to convert null to "" for all runtime entities
- This ensures existing default tenant data is properly migrated per ADR-0008
- Note: Similar migrations needed for PostgreSql, MySql, Sqlite, and Oracle providers

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Clarify tenant handling logic in `ElsaDbContextBase` with new ADR references.

* Add tenant ID convention analysis documents and quick reference guide

* Implement tenant-agnostic functionality across modules

- Introduce `AgnosticTenantId` constant to manage tenant-agnostic entities.
- Modify entity handling logic to respect tenant-agnostic designations.
- Adjust workflow processing to include tenant-agnostic workflows.
- Update caching and activity descriptor logic to accommodate the `AgnosticTenantId`.

* Refactor tenant management and registry logic in `ActivityRegistry` for improved clarity and separation of tenant-specific and tenant-agnostic activity descriptors. Remove `TestTenantResolver` and update workflow definition handling for tenant support.

* Refactor `ActivityRegistry`: prioritize tenant-specific descriptors over tenant-agnostic and simplify descriptor retrieval logic.

* Improve async handling in `CommandHandlerInvokerMiddleware` to await tasks without blocking

* Update ADR to use asterisk as sentinel value for tenant-agnostic entities

Replace the previous convention of using `null` for tenant-agnostic entities with an asterisk (`"*"`) for improved clarity and system architecture. Updated ADR documentation, TOC, and dependency graph accordingly.

* Remove migration `ConvertNullTenantIdToEmptyString` and its associated designer file to clean up the codebase.

* Refactor `ActivityRegistry`: streamline activity descriptor removal logic and simplify tenant ID checks.

* Update Elsa.sln

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

* Simplify `RefreshDescriptorsAsync` by removing unnecessary local variable `currentTenantId`.

* Remove unused `currentTenantId` variable from `ActivityRegistry`.

* Add detailed semantic flow and key points to ADR 0009

Document the tenant ID flow from entity creation to query, emphasizing normalization and tenant-agnostic workflows. Update semantic flow diagrams and provide testing considerations for preserving `"*"` values in multi-tenant scenarios.

* Remove outdated Tenant ID Analysis and associated documents

* Add security-by-default design for tenant-agnostic entities in ADR

Enhance Architecture Decision Record to detail explicit requirements for tenant-agnostic database entities, highlighting differences between in-memory activity descriptors and persistent entities. Emphasize importance of setting `TenantId = "*"` to prevent accidental data leakage.

* Normalize tenant ID grouping in `ActivityRegistry` to unify null and agnostic IDs, reducing redundant processing.

* Refactor `SignalManager`: improve timeout handling and streamline signal task cancellation.

* Update src/modules/Elsa.Workflows.Core/Models/TenantRegistryData.cs

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

* Update src/modules/Elsa.Workflows.Core/Services/ActivityRegistry.cs

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

* Refactor tests to use `Tenant.AgnosticTenantId` instead of `null` for tenant-agnostic descriptors.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Enhance logging in recurring tasks: add error handling and logger support to prevent crashes in scheduled timers.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2026-02-02 10:59:01 +01:00
Sipke Schoorstra af1e4e835e
Remove duplicate reference to tenant-deleted-event ADR in solution file. 2026-01-30 20:31:40 +01:00
Sipke Schoorstra b09a564812
Fix Multitenancy Support and Normalize Tenant ID Handling (#7217)
* Enable multitenancy support and normalize tenant ID handling.

- Activate multitenancy in `Program.cs`.
- Introduce `NormalizeTenantId` method for consistent tenant ID usage.
- Update tenant-related classes and features to support normalization logic.

* Add ADR for adopting empty string as the default tenant ID

- Standardized the tenant ID for the default tenant to use an empty string (`""`) instead of `null`.
- Documented the rationale and migration considerations in ADR 0007.
- Updated ADR table of contents and graph for new entry.

* Apply suggestion from @sfmskywalker

* Update doc/adr/graph.dot

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

* Normalize spacing and improve readability in `Program.cs`. Fix multitenancy condition formatting.

* Fix ADR numbering and update TOC

* Add ADRs for flowchart execution model, tenant deletion event, merge modes, and default tenant ID

- Introduced ADR 0005: Token-centric flowchart execution model for improved loop and join handling.
- Added ADR 0006: Tenant Deleted event for distinct handling of tenant removal.
- Documented ADR 0007: Explicit merge modes for flowchart joins, improving reliability and configurability.
- Included ADR 0008: Standardization of empty string as the default tenant ID for consistency and clarity.

* Add unit tests for tenant ID normalization and multitenancy pipeline invoker

- Added comprehensive unit tests for tenant ID normalization to ensure consistent handling of null, empty, and valid IDs.
- Introduced tests for the multitenancy pipeline invoker covering various tenant resolution scenarios.
- Updated solution to include new unit testing projects for `Elsa.Tenants` and `Elsa.Common`.

* Update unit tests for `ActivityConstructionResult`

- Refactor test parameterization to verify `HasExceptions` property more explicitly.
- Simplify exception creation logic in helper methods.
- Improve test assertions by combining act and assert phases where applicable.

* Enable configuration-based multitenancy with tenant-specific settings

- Introduced a configuration-based tenant provider to streamline tenant initialization and customization.
- Added tenant ID handling filters to ensure tenant ID is applied and filtered automatically.
- Deprecated the `CommonPersistenceFeature` in favor of modular persistence feature extension.

* Update database indexes to include `TenantId` for multitenancy support

- Added `TenantId` to unique constraints on `Triggers` table across all EFCore providers.
- Adjusted index names to reflect the updated constraints.
- Updated trigger configuration to ensure uniqueness includes `TenantId`.

* Add tenant filtering to `DefaultWorkflowDefinitionStorePopulator`

- Introduced `ITenantAccessor` to support tenant-specific filtering of workflow definitions.
- Updated logic to skip workflows not matching the current tenant.

* Update doc/adr/toc.md

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

* Remove `CommonPersistenceFeature` as it has been deprecated

* Add tenant-specific filtering to workflow import logic in `DefaultWorkflowDefinitionStorePopulator`

* Replace hardcoded tenant ID with `Tenant.DefaultTenantId` in integration tests

* Update database indexes and migration logic to support `TenantId` for multitenancy

- Added `TenantId` to unique constraints on the `Triggers` table and updated index names.
- Included logic to drop outdated indexes without `TenantId` during migration.
- Adjusted tests to account for `TenantId` in workflow identity and indexing scenarios.

* Remove `TenantId` from workflow identity construction in concurrent trigger indexing tests

* Introduce `SelectiveMockLockProvider` for precise lock mocking in tests

- Added `SelectiveMockLockProvider` to allow targeted lock mocking without affecting unrelated background operations.
- Updated test services to use `SelectiveMockLockProvider` in place of `TestDistributedLockProvider`.
- Refactored `DistributedLockResilienceTests` to support selective mocking for deterministic and reliable assertions.

* Update Elsa.sln

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

* Normalize tenant ID handling in `DefaultWorkflowDefinitionStorePopulator` for consistent filtering

* Refactor `TenantResolverResult` to support explicit resolved/unresolved state handling

- Updated `TenantResolverResult` to include an explicit `_isResolved` property.
- Adjusted `ResolveTenantId()` and `IsResolved` logic for improved clarity and robustness.
- Simplified tenant resolution invocation in `TenantResolverBase`.
- Removed redundant normalization in `DefaultTenantResolverPipelineInvoker`.

* Normalize tenant ID handling in `DefaultWorkflowDefinitionStorePopulator` and `ClrWorkflowsProvider`.

* Refactor `DefaultWorkflowDefinitionStorePopulatorTests`: streamline object initializations and add tenant-specific test coverage for `PopulateStoreAsync`.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-30 19:54:13 +01:00
Sipke Schoorstra ad87ab96fd
Improves HTTP context loss error handling (#7187)
* Remove bookmark-based resumption logic for lost HTTP context scenarios in `WriteHttpResponse` and `WriteFileHttpResponse`.

Simplify error handling by throwing descriptive exceptions for workflows resuming without an available HTTP context.

* Add integration tests for HTTP context loss scenarios in `WriteHttpResponse` and `WriteFileHttpResponse`.

* Add integration tests for handling HTTP context loss in response activities.

* Replace bookmark-based logic with fault exceptions in tests for `WriteHttpResponse` and `WriteFileHttpResponse` when HTTP context is unavailable.

* Update agent-logs/http-context-loss-error-messaging.md

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

* Update test/integration/Elsa.Http.IntegrationTests/Elsa.Http.IntegrationTests.csproj

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

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-12 16:51:30 +01:00
Sipke Schoorstra b577279321
Improves tenant task management with dependencies (#7174)
* Consolidate tenant task lifecycle logic into `TenantTaskManager` and remove obsolete task event handlers (`RunStartupTasks`, `RunBackgroundTasks`, `StartRecurringTasks`). Introduce `TopologicalTaskSorter` for dependency-based task execution.

* Handles multiple tasks of the same type

Updates the topological task sorter to handle multiple tasks of the same type.

Previously, the sorter assumed a one-to-one mapping between task types and task instances, which caused issues when multiple tasks of the same type were present.
Now, it groups tasks by type and adds them to the result in the correct order.

* Add unit tests for `TopologicalTaskSorter`

Introduce `Elsa.Common.UnitTests` project with comprehensive test coverage for `TopologicalTaskSorter`, including dependency resolution, circular dependency handling, and task ordering scenarios. Update `Elsa.sln` to include the new test project.

* Update src/modules/Elsa.Common/Multitenancy/EventHandlers/TenantTaskManager.cs

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

* Unwrap background task continuation in `TenantTaskManager` to ensure proper task execution tracking.

* Update src/modules/Elsa.Common/Helpers/TopologicalTaskSorter.cs

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

* Refactor `TryGet` method to prioritize memory register lookup and update `Output` constructor to use `MemoryBlockReference`.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-29 20:49:24 +01:00
Sipke Schoorstra ca268c16ad
Enhances distributed lock handling with resilience (#7161)
* Add retry mechanism for distributed locks with transient error handling and logging

- Introduced Polly-based retry pipeline for distributed lock acquisition in `DistributedWorkflowClient` to handle transient errors such as network issues or database connection failures.
- Added detailed logging for retry attempts and lock release errors.
- Updated project dependencies to include Polly.

* Refactor transient exception handling to shared resilience module.

Migrated transient exception detection logic from scheduling module to a new shared resilience module. Updated services, jobs, and features to utilize the centralized `ITransientExceptionDetectionService`. This change improves maintainability and promotes reusability across modules.

* Add unit tests for transient exception detection and resilience strategy evaluation.

- Introduced comprehensive unit tests for `DefaultTransientExceptionDetector`, `ResilienceStrategyCatalog`, `ResilienceStrategyConfigEvaluator`, and `TransientExceptionDetectionService`.
- Added helper classes and test data factories to facilitate reusable test patterns for resilience modules.
- Updated solution to include `Elsa.Resilience.Core.UnitTests` project.

* Add component tests for distributed lock resilience

- Introduced new tests to verify retry behavior during transient lock acquisition and release failures.
- Added `TestDistributedLockProvider` and related mocks for simulating transient failures.
- Updated `WorkflowServer` test services to support the new distributed lock test scenarios.

* Refactor distributed lock resilience tests

- Consolidated test logic: streamlined test providers, injected services, and reusable test patterns.
- Simplified `TestDistributedLockProvider` implementation with enhanced initialization and failure simulation.
- Reorganized tests for transient acquisition/release failures to use parameterized `Theory` for improved maintainability.

* Refactor transient exception handling: rename interfaces and classes for consistency, update references across codebase, and improve code readability.

* Apply suggestion from @Copilot

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

* Simplify WorkflowServer setup and DistributedLockResilienceTests by replacing IDistributedLockProvider with TestDistributedLockProvider.

* Remove unused `using` directives in unit tests to improve code cleanliness.

* Remove `TransientExceptionTypes` helper and inline its usage in tests for improved maintainability.

* Add descriptive `DisplayName` attributes to unit tests for improved test clarity.

* Fix redundant exception checking in TransientExceptionDetector (#7162)

* Initial plan

* Fix redundant exception checking in TransientExceptionDetector

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Extract MaxRetryAttempts constant in DistributedLockResilienceTests (#7164)

* Initial plan

* Extract MaxRetryAttempts constant to eliminate hardcoded magic number

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Make TestDistributedLockProvider thread-safe with Interlocked operations (#7163)

* Initial plan

* Make TestDistributedLockProvider thread-safe using Interlocked operations

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

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

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

* Update test/component/Elsa.Workflows.ComponentTests/Scenarios/DistributedLockResilience/DistributedLockResilienceTests.cs

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

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

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

* Update src/modules/Elsa.Resilience.Core/Services/DefaultTransientExceptionStrategy.cs

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

* Include `CancellationToken` in distributed lock handling methods for improved cancellation support.

* Initial plan (#7168)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Cache detector list in TransientExceptionDetector to avoid repeated allocations (#7167)

* Initial plan

* Cache detector list in field to avoid repeated allocations

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Use IReadOnlyList instead of List for better intent expression

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Fix TestDistributedLockProvider registration to properly decorate IDistributedLockProvider (#7166)

* Initial plan

* Fix TestDistributedLockProvider registration to use Decorate pattern and fix variable reference bug

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Add runtime check for TestDistributedLockProvider registration

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Refactor `DistributedWorkflowClient` to simplify `Lazy<ResiliencePipeline>` initialization.

* Add integration tests for DistributedWorkflowClient lock resilience (#7165)

* Initial plan

* Fix compilation error: use correct parameter name transientExceptionDetector

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Add integration tests for DistributedWorkflowClient lock resilience

- Add SimpleWorkflow for testing distributed lock scenarios
- Add tests exercising RunInstanceAsync with transient lock failures
- Verify retry logic works correctly with actual workflow execution
- Test both acquisition and release failure scenarios
- Decorate IDistributedLockProvider to use TestDistributedLockProvider

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Address code review feedback

- Add explanatory comment for TestDistributedLockProvider cast
- Remove unnecessary blank line for consistent formatting

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>

* Simplify transient exception strategy by refactoring message pattern matching logic.

* Enhance distributed lock mock to support per-lock failure configuration and improve resilience tests.

* Refactor `TestDistributedLockProvider` to streamline failure handling logic and improve code clarity.

* Remove unused methods and redundant test case from `DistributedLockResilienceTests`.

* Refactor `DistributedLockResilienceTests` to simplify workflow client creation, consolidate assertion logic, and remove redundant test cases.

* Format `ResilienceStrategyCatalogTests` by removing redundant line breaks in test setup.

* Refactor `TransientExceptionDetectorTests` to simplify test setup, consolidate test cases, and remove redundant logic.

* Handle `InvalidOperationException` in `XunitLogger` to suppress logging errors during inactive tests.

* Update workflows to use .NET 10 and adjust resilience tests project configuration.

* Refactor distributed runtime feature and integrations to improve resilience handling, configure services fluently, and add cancellation safeguards in background services.

* Update `base_version` to `3.7.0` in GitHub workflow configuration.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2025-12-29 19:53:48 +01:00
Sipke Schoorstra b854c0272a
Remove unused Docker services, volumes, and solution references.
Removed unnecessary Docker services, configuration files, and volumes from `docker-compose.yml`. Cleaned up unused project references in `Elsa.sln`. Streamlined local development setup by eliminating redundant resources.
2025-12-19 19:31:01 +01:00
Sipke Schoorstra 9eea009133
Remove elsa-server.yml workflow and update solution configuration. 2025-12-19 19:27:21 +01:00
Sipke Schoorstra a1d4e541fc
Add Elsa Script DSL (#7076)
* Update packages.yml

* Update elsa-server-and-studio.yml

* Update elsa-server.yml

* Update elsa-studio.yml (#6715)

* Update ListWorkflowDefinitionsRequest.cs (#6761)

Remove unnecessary line breaks

* Correct namespace and import for `ConfigureEngineWithVariableTypes`.

* Resolves build issues, update package versions and restructure project references

- Updated multiple package versions in `Directory.Packages.props` for better dependency management, including `BenchmarkDotNet`, `FastEndpoints`, and `Microsoft.Extensions.Http.Resilience`.
- Minor version upgrade for `System.Formats.Asn1` in `_build.csproj`.
- Replaced project reference to `Elsa.csproj` with `Elsa.IO.Http.csproj` in `Elsa.ServerAndStudio.Web.csproj`, enhancing modularity.
- Added new using directive for `Elsa.IO.Http.Features` in `Program.cs` to support new HTTP functionalities.

* Remove unused project references from Elsa.sln

These changes indicate that the associated projects or dependencies are no longer needed or have been replaced by other components in the solution.

* Rename copilot-setup-steps.yml.yml to copilot-setup-steps.yml

* Update RawStringContent encoding in JsonContentFactory (#6786)

* Update RawStringContent encoding in JsonContentFactory

Modified the instantiation of `RawStringContent` to use a
new `UTF8Encoding` instance with `encoderShouldEmitUTF8Identifier`
set to `false`, affecting the handling of the UTF-8 byte order
mark (BOM) in serialized JSON content. Fixes a bug with content length being different than expected.

* Refactor JsonContentFactory to reuse UTF8Encoding

Introduced a private static readonly field `_utf8Encoding` in the `JsonContentFactory` class to improve code readability and performance. This change replaces the instantiation of `UTF8Encoding` in the `CreateHttpContent` method, allowing for the reuse of the same encoding instance.

---------

Co-authored-by: Max Brooks <Max@compyl.com>

* Enhance thread safety with ConcurrentDictionary usage (#6760)

* Enhance thread safety with ConcurrentDictionary usage

Replaced `IDictionary` with `ConcurrentDictionary` for
both `_scheduledTasks` and `_scheduledTaskKeys` to
improve thread safety in a multi-threaded environment.

Updated methods `RegisterScheduledTask`,
`RemoveScheduledTask`, and `RemoveScheduledTasks` to
utilize the `Remove` method of `ConcurrentDictionary`,
ensuring safe and efficient removal of scheduled tasks.

* Refactor task registration and removal logic

Updated `RegisterScheduledTask` to use `AddOrUpdate` for streamlined task management. This change simplifies the addition and updating of scheduled tasks by consolidating logic into a single operation. Introduced `RemoveScheduledTask` method to handle task removal by name, improving code organization and clarity.

* Improve task removal handling in LocalScheduler

Modified the `LocalScheduler` class to enhance the removal process of scheduled tasks from the `_scheduledTaskKeys` collection. The removal operation now captures the result in a variable and includes a conditional check to log a warning if the task was not found, improving error handling and debugging capabilities.

* Refactor task removal in LocalScheduler

Updated the removal process for scheduled tasks in `_scheduledTasks`.
The new implementation collects all corresponding keys and attempts to remove them individually, logging warnings for any failures. This enhances error handling and provides better debugging information.

---------

Co-authored-by: Max Brooks <Max@compyl.com>

* Add IAsyncEnumerable check to ItemSourceActivityExecutionContextExtensions.GetItemSource (#6897)

* Use FullName in WorkflowDictionary (#6923)

* Fixed ParentWorkflowInstanceId not being set (#7029)

Co-authored-by: Peter Klooster <peter.klooster@autotaalglas.nl>

* Remove unused solution projects and update package references

- Deleted several project references from `Elsa.sln` to clean up the solution.
- Updated `Directory.Packages.props` for consistency and alignment with the latest package versions.

* Simplify CI pipeline by removing `Test` step from `Compile+Test+Pack` process.

* Initial plan

* Add ElsaScript DSL module with parser and compiler

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Add integration tests for ElsaScript DSL

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Add comprehensive documentation for ElsaScript DSL

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Refactor workflow activity instantiation logic

- Removed `ActivityFactory` and its related interfaces and extensions.
- Introduced `ActivityActivator` for handling activity creation.
- Extended AST with support for comprehensive workflow structures:
  - Added nodes for flowcharts, if/else, loops, and variable declarations.
- Updated `IElsaScriptCompiler` to use asynchronous methods.
- Expanded `ElsaScriptParser` to simplify syntax for `UseNode` and argument parsing.
- Adjusted compiler and parser for compatibility with new workflow AST model.

* Refactor test method names for clarity and add new compiler and parser tests

- Updated method names in `CompilerTests` and `ParserTests` for better readability and description of test intent.
- Added tests for compiler and parser:
  - Support for workflows without the `workflow` keyword.

* Refactor `ElsaScriptParser` to improve statement parsing and introduce a tokenizer

- Added `TokenizeStatements` method to split source into statements for enhanced parsing accuracy.
- Updated logic to process statements instead of raw lines, reducing parsing complexity and improving reliability.
- Improved handling of workflow and statement parsing, including edge cases with braces, parentheses, and string literals.

* Introduce ElsaScript support for BlobStorage workflow provider

- Added the `Elsa.WorkflowProviders.BlobStorage.ElsaScript` module to enable ElsaScript-based workflow definitions for BlobStorage.
- Implemented `ElsaScriptBlobWorkflowFormatHandler` for parsing ElsaScript workflows stored in BlobStorage.
- Extended `ElsaScriptParser` to leverage Parlot for improved DSL parsing.
- Introduced `IBlobWorkflowFormatHandler` to centralize workflow format handling and parsing.
- Updated `Elsa.Server.Web` to reference the new module and include an ElsaScript "Hello World" example workflow.

* Refactor ElsaScript services, update logging, and improve workflow handling

- Changed `ElsaScriptCompiler` service registration from `Singleton` to `Scoped` for better dependency management.
- Enhanced the "Hello World" example workflow and added `CopyToOutputDirectory` configuration.
- Removed unused namespaces and adjusted references in multiple projects to improve maintainability.
- Updated logging levels in `appsettings.json` to reduce unnecessary debug output.
- Improved `PolymorphicObjectConverter` by removing redundant dependencies.
- Added missing references to enhance feature support and ensure compatibility.

* Refactor activity instantiation and improve argument handling in `ElsaScriptCompiler`

- Added support for positional arguments with constructor matching logic.
- Refactored `InstantiateActivityUsingConstructor` to enhance activity creation.
- Updated `ActivityDescriptor` and related types to include `ClrType` for streamlined activity resolution.
- Simplified `TypedActivityProvider` by annotating it with `[UsedImplicitly]`.
- Adjusted `ElsaScriptParser` to remove unnecessary options from string literal definitions.

* Add HTTP-enabled "Hello World" workflow and support for additional HTTP activity constructors

- Introduced a new ElsaScript example workflow `hello-world-http.elsa` with an HTTP endpoint and response.
- Enhanced `HttpEndpoint` and `WriteHttpResponse` activities with additional constructors for improved flexibility.
- Updated project to include the new workflow in the output directory.

* Enhance `ElsaScriptParser` with a custom parser to handle nested raw expressions for ElsaScript workflows

- Introduced `RawExpressionParser` to parse raw text after `=>` up to a matching closing parenthesis.
- Updated `elsaExpressionWithLang` and `elsaExpressionWithoutLang` to use `RawExpressionParser`.
- Trimmed whitespace in parsed expressions.
- Added integration and parser tests for complex workflows with variables and expressions.
- Updated example workflow `hello-world-http.elsa` to demonstrate expression usage.
- Added `Elsa.Http` module reference to enable HTTP-based activities.

* Update "Hello World" workflow to simplify naming and enhance response logic

- Renamed workflow from `HelloWorldHttpDsl2` to `HelloWorldHttpDsl`.
- Updated HTTP endpoint path to `/hello-world-dsl` for consistency.
- Improved response logic by utilizing `getMessage()` JavaScript function.

* Add support for `OriginalSource` in workflow materialization and enhance ElsaScript materializer

- Introduced `OriginalSource` property in `WorkflowDefinition` and `MaterializedWorkflow` for preserving original source representation (e.g., ElsaScript, JSON, YAML).
- Added `ElsaScriptWorkflowMaterializer` implementation to materialize workflows directly from ElsaScript source.
- Updated `DefaultWorkflowDefinitionStorePopulator` to determine `StringData` or `OriginalSource` based on materialized workflow format.
- Enhanced `WorkflowDefinitionMapper` to support symmetric round-tripping with `OriginalSource`.
- Registered `ElsaScriptWorkflowMaterializer` in `ElsaScriptFeature` for dependency injection.
- Updated `JsonBlobWorkflowFormatHandler` and added `OriginalSource` support for round-trip preservation.
- Simplified `ElsaScriptParser` by aligning variable and parser naming.

* Update V3_6 migrations for PostgreSQL, MySQL, and Oracle databases and associated designer files.

* Handle disposal and race conditions in `ScheduledCronTask`

- Added `_disposed` flag to prevent accessing disposed resources.
- Updated `_executionSemaphore` and `_scopeFactory` logic to safely handle `ObjectDisposedException`.
- Enhanced task scheduling and timer disposal with additional safeguards against race conditions.
- Modified tests to ensure proper disposal and logging behavior when handling edge cases.

* Add support for metadata in ElsaScript workflows and enhance parser and compiler functionality

- Introduced metadata syntax in ElsaScript workflows (e.g., `DisplayName`, `Description`, `Version`) to enable metadata-driven behavior.
- Enhanced `ElsaScriptCompiler` to process metadata and properly integrate it into `Workflow` objects.
- Updated `ElsaScriptParser` to parse program-level AST with support for multiple workflows and global use statements.
- Refactored tests to validate metadata parsing and ensure backward compatibility with existing workflows.
- Added new test cases to cover scenarios like metadata parsing, compilation, and multi-workflow programs.

* Add support for `foreach` loops in ElsaScript and remove `let` keyword

- Introduced `foreach` loop syntax in `ElsaScriptParser` and `ElsaScriptCompiler`, enabling iteration over collections with optional variable declaration.
- Updated `ForNode` and `ForEachNode` to include a `DeclaresVariable` flag for improved variable handling.
- Removed support for the `let` keyword in variable declarations, streamlining syntax to use `var` and `const` only.
- Enhanced `for` loop syntax to support optional `var` declaration and block or single-statement bodies.
- Refactored test cases to validate `foreach` and `for` loop enhancements and ensure backward compatibility.

* Simplify ElsaScript workflow syntax by removing redundant quotes in workflow identifiers and updating `for` loop syntax for clarity and consistency.

* Remove redundant quotes from workflow identifiers in integration tests

* Simplify Elsa scripts and improve error handling

- Removed redundant braces in workflow declarations for streamlined syntax.
- Enhanced logging in `JsonBlobWorkflowFormatHandler` and `ElsaScriptBlobWorkflowFormatHandler` to warn on parsing errors and provide context.
- Updated configuration to log errors for `Elsa.Workflows.ActivityRegistry`.
- Refined "Hello World" and "For Loop" workflows for clarity and added improved loop handling.

* Refine Elsa workflows and update compiler logic

- Simplified "Hello World" workflow by adding braces and improving consistency.
- Adjusted "For Loop" workflow to rename and clarify logic, including expression updates and variable handling.
- Fixed compiler mapping of `"cs"` to `"CSharp"` for better clarity.
- Enhanced "Hello World HTTP" workflow to correctly reference `variables.message` in expressions.

* Add flowchart support in ElsaScript parser, compiler, and integration tests

- Introduced `flowchart` syntax in `ElsaScriptParser` to support flowchart-based workflows.
- Updated `ElsaScriptCompiler` to compile `flowchart` nodes with labeled activities, connections, entry points, and variables.
- Added integration tests for parsing and compiling empty and simple flowcharts.
- Enhanced `FlowchartNode` and `LabeledActivityNode` for better representation of flowchart structures.
- Improved error handling and logging for invalid flowchart configurations.

* Add tests for compiling and parsing flowcharts with nodes, connections, and block nodes in ElsaScript

- Added integration tests for compiling and validating flowchart structures, including activities, connections, and entry points.
- Implemented parser tests for parsing flowcharts with node connections and block nodes.
- Updated project files to include new workflow examples for testing.

* Add Parlot package and update project file in integration tests

- Added `Parlot` package version `0.0.27` to `Directory.Packages.props`.
- Updated integration test project file to include a new `Include` directive for better targeting.

* Update Parlot package to version 1.5.2 in Directory.Packages.props

* Remove `elsa-server-and-studio.yml` workflow and update solution file

- Deleted `elsa-server-and-studio.yml` workflow as it's no longer needed.
- Updated `Elsa.sln` to remove reference to the deleted workflow.

* Remove `elsa-studio.yml` workflow and update solution and packages

- Deleted `elsa-studio.yml` workflow as it's no longer used.
- Updated `Elsa.sln` to remove reference to the deleted workflow.
- Changed `base_version` in `packages.yml` from `3.7.0` to `3.6.0`.

* Downgrade Docker image in `elsa-server.yml` workflow from `v3.7.0-preview` to `v3.6.0-preview`

* Update Docker image tag in `elsa-server.yml` workflow from `v3.6.0-preview` to `v3.6-preview`

* Add logging support to `LocalScheduler` and replace `Debug.WriteLine` with `ILogger`

* Remove unused `System.Collections.Generic` and `Elsa.Extensions` imports in `LocalScheduler`

- Cleaned up unnecessary using directives to improve code readability and maintainability.
- Minor whitespace adjustment for consistent formatting.

* Remove unnecessary whitespace in `LocalScheduler` for consistent formatting

* Improve exception handling in blob workflow format handlers

- Updated exception handling in `ElsaScriptBlobWorkflowFormatHandler` and `JsonBlobWorkflowFormatHandler` to gracefully catch and log all exceptions during workflow parsing.
- Adjusted comments to clarify behavior for invalid user-provided files, ensuring the workflow loading process is not disrupted.

* Refactor blob workflow format handlers to use `SupportedExtensions` for improved file filtering

- Added `SupportedExtensions` property to all blob format handlers to optimize blob storage browsing.
- Simplified `CanHandle` logic by removing extension checks, leveraging `SupportedExtensions` for initial filtering.
- Updated comments for clarity and consistency across handlers.

* Refactor `DefaultWorkflowDefinitionStorePopulator` to simplify `stringData` assignment logic and improve readability

* Remove outdated comment in `CompilerTests` about skipped tests

* Apply suggestion from @Copilot

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

* Refactor `ElsaScriptCompiler` to streamline type conversion logic, improve language mapping, and enhance asynchronous flowchart compilation

* [WIP] Update ParseError printing based on feedback (#7082)

* Initial plan

* Fix ParseError formatting to use Message and Position properties

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Replace `as` casts with direct casts in ParserTests for null safety (#7083)

* Initial plan

* Replace 'as' casts with direct casts in ParserTests for better null safety

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Fix Oracle column types for OriginalSource and other large text fields (#7079)

* Initial plan

* Fix Oracle OriginalSource and StringData column types to handle large data

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Refactor tests to replace type checks with `Assert.IsType` for improved clarity and type safety

* Initial plan (#7080)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

* Add `Parlot` package reference and update solution structure by removing and reorganizing projects and workflows.

* Set default expression language to "JavaScript" in `ElsaScriptCompiler`.

* Add integration test to verify default expression language resets between ElsaScript compilations

* Simplify UTF-8 encoding in JsonContentFactory (#7081)

* Initial plan

* Remove explicit UTF8Encoding in JsonContentFactory and use Encoding.UTF8

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Fix test to use Encoding.UTF8.GetByteCount for multi-byte character support

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: Ender <37611092+zengande@users.noreply.github.com>
Co-authored-by: Matt <knibbsy10@live.com>
Co-authored-by: Max Brooks <45081361+MaxBrooks114@users.noreply.github.com>
Co-authored-by: Max Brooks <Max@compyl.com>
Co-authored-by: FuJa0815 <30809803+FuJa0815@users.noreply.github.com>
Co-authored-by: Peter Klooster <crashkonijn@gmail.com>
Co-authored-by: Peter Klooster <peter.klooster@autotaalglas.nl>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-25 19:57:50 +01:00
Sipke Schoorstra 3340e14b74
Improves Fork activity and break signal handling (#7104)
* Add unit and integration tests for `Container` activity, covering behavior such as variable scoping, child activity execution, and mixed variable types.

* Refactor `RunWorkflowAndCaptureOutput` method in `ContainerTests` for better code organization

* Move `Sequence` activity tests to a dedicated namespace and add new unit and integration tests for enhanced coverage.

- Deleted outdated `SequenceTests` and related workflows.
- Introduced `SequenceActivity` namespace with improved organization.
- Added comprehensive unit and integration test coverage for sequential execution, nested sequences, conditional breaking, variables, and dynamic activities.

* Relocate `SequenceActivity` tests to `Activities` namespace to improve organization and update references in related test classes.

* Refactor `SequenceTests` to move `DynamicSequenceWorkflow` to its own file for better test organization.

* Extract `TestContainer` to `Elsa.Testing.Shared.Activities` for reuse across test projects.

* Add unit and integration tests for `Break` activity; refactor workflow tests for improved organization

- Introduced `BreakInForkWorkflow` and deprecated `BreakWhileForkWorkflow`.
- Added `BreakTests` unit tests to validate behavior of the `Break` activity, including terminal node implementation and execution completion.
- Enhanced integration tests for `Break` activity, covering multiple looping constructs (`ForEach`, `For`, `While`, `Fork`) and nested workflows.
- Updated `Fork` activity to handle the `BreakSignal` asynchronously.
- Simplified workflow definitions by removing redundant constructors and using concise variable initialization syntax.
- Improved test clarity with better organization, comments, and consistent naming conventions.

* Refactor `Fork` activity tests and workflows for improved organization and coverage

- Relocated `BasicForkWorkflow` and `JoinAnyForkWorkflow` to `Fork/Workflows` namespace.
- Introduced `EmptyForkWorkflow` to test Fork behavior with no branches.
- Enhanced `ForkTests` with scenarios for `Fork` execution with different join modes and branch configurations.
- Refactored `Fork` activity to handle empty branches and simplified `BreakSignal` handling.
- Improved consistency and clarity of test cases, including better assertions and comments.

* Update test/integration/Elsa.Workflows.IntegrationTests/Activities/Break/BreakTests.cs

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

* Update test/integration/Elsa.Workflows.IntegrationTests/Activities/Break/BreakTests.cs

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

* Update test/integration/Elsa.Workflows.IntegrationTests/Activities/Break/BreakTests.cs

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

* Update test/integration/Elsa.Workflows.IntegrationTests/Activities/Fork/ForkTests.cs

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

* Update test/integration/Elsa.Workflows.IntegrationTests/Activities/Fork/ForkTests.cs

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

* Update GitHub Actions workflow to use .NET 10.x

* Remove outdated GitHub workflows and update configurations to .NET 10.x

* Remove unused result variable assignments in integration tests (#7105)

* Initial plan

* Remove unused result variable assignments in BreakTests and ForkTests

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
2025-11-25 19:29:02 +01:00
FuJa0815 c017082f01
Added IEnumerableTypeConverter (#7020)
* Added IEnumerableTypeConverter

* fixed bug and added tests

* Add resource disposal mechanism in ScheduledCronTask

- Introduced `_disposed` flag to prevent execution after disposal.
- Updated disposal logic to ensure proper release of resources.
- Adjusted unit tests to verify new disposal behavior and prevent unintended timer actions.

* Enhance scheduling tasks with edge case handling and disposal improvements

- Added `_disposed` flag to `ScheduledRecurringTask` and `ScheduledSpecificInstantTask` to prevent execution after disposal.
- Adjusted timer setup logic to handle zero/negative delays with a minimum delay of 1ms.
- Updated disposal logic to ensure proper resource cleanup even during timer callbacks.
- Introduced extensive unit tests for edge cases such as small, zero, or negative delay scenarios and proper disposal behavior.

* Update test/component/Elsa.Workflows.ComponentTests/Scenarios/VariablesArray/Activities/RemoveTopElementStep.cs

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

* Update src/modules/Elsa.Common/Serialization/IEnumerableTypeConverter.cs

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

* Update src/modules/Elsa.Common/Serialization/IEnumerableTypeConverter.cs

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

* Add integration tests for EnumerableTypeConverter and update solution file

- Introduced `Elsa.Common.IntegrationTests` project for testing serialization behavior in `EnumerableTypeConverter`.
- Added tests to verify proper handling of strings, byte arrays, and collections during JSON serialization.
- Registered `EnumerableTypeConverter` in `DefaultFormattersFeature`.
- Renamed `IEnumerableTypeConverter` to `EnumerableTypeConverter` for consistency.
- Updated solution file to include the new integration test project.

---------

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-12 11:07:33 +01:00
Sipke Schoorstra ecf5b390f1
Remove Elsa.ServerAndStudio.Web and related projects
- Deleted Elsa.ServerAndStudio.Web alongside its components, configurations, and projects: Elsa.Studio.Web, ElsaStudioWebAssembly.
- Updated solution file to exclude removed projects.
- Simplified folder structure by eliminating unused files, enums, activities, settings, and resources.
2025-11-09 14:16:52 +01:00
Sipke Schoorstra f51f1e918e
Add extensive unit and component tests for scheduling activities (#7036)
* Add DispatchWorkflow tests with new workflow definitions

- Introduced multiple workflow definitions with varied scenarios including input handling, correlation IDs, and fault handling.
- Enhanced `DispatchWorkflowsTests` with comprehensive test cases to validate `DispatchWorkflow` behavior under different configurations.
- Updated existing workflows and tests for improved structure, readability, and accuracy.
- Refactored and renamed related workflows for consistency across test suites.

* Update test/component/Elsa.Workflows.ComponentTests/Scenarios/Activities/DispatchWorkflows/DispatchWorkflowsTests.cs

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

* Refactor DispatchWorkflowsTests for readability and maintainability

- Replaced hardcoded constants with named variables for improved clarity.
- Enhanced assertions using utility methods like `Assert.Single` for cleaner code.
- Updated WriteLine activity tests to handle null values reliably.
- Introduced timeout handling for child workflow execution.

* Update GUID length validation in JintJavaScriptFunctionBehaviorTests

- Adjusted `shortGuid` length assertion to accommodate a range of 19-22 characters instead of 20-22.

* Add extensive unit and component tests for scheduling activities

- Introduced unit tests for `Cron`, `Delay`, `Timer`, and `StartAt` scheduling activities, covering general usage and corner cases.
- Added component tests validating `Cron`, `Delay`, `Timer`, and `StartAt` workflows within broader scenarios, focusing on workflow execution, blocking, and resumption of activities.
- Enhanced test project structures with new folder setups aligning to activity categories.
- Updated namespaces and project files to match the new structure and added validation for scheduling logic.

* Refactor Timer activity tests for consistency and reusability

- Extracted shared logic for timer activity tests into `TimerActivityTestBase`.
- Refactored `DelayTests`, `TimerTests`, `CronTests`, and `StartAtTests` to inherit from `TimerActivityTestBase`.
- Removed redundant code and improved test consistency across all timer activity test cases.
- Cleaned up unused imports and optimized namespaces.

* Remove unused folder references from test project files

* [WIP] Update unit and component tests for scheduling activities (#7037)

* Initial plan

* Replace ContainsKey + indexer with TryGetValue in CronTests

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

* Fixing build after merge

* Remove DispatchWorkflowsTests and related references from the test suite

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Co-authored-by: lucas.hipolito <lukhipolito@yahoo.com.br>
2025-11-07 21:54:50 +01:00
lukhipolito-nexxbiz fcd0b5ae9a
Feat/unit test coverage sendhttprequest (#6961)
* Unit test coverage for SendHttpRequest + useful extensions

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

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

* Update test/unit/Elsa.Activities.UnitTests/HTTP/SendHttpRequestTests.cs

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

* Update test/unit/Elsa.Activities.UnitTests/HTTP/SendHttpRequestTests.cs

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

* Improvements on unit test and documentation for http

* Update doc/qa/test-guidelines.md

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>

* Improvements on maintainability of sendhttprequest unit tests

* Improving tests and scheduled activity evaluation for activity context

* Refactor and splitting unnecessary grouped tests

* Improvements on SendHttp Unit tests

* Improvements on tests

* Update test/unit/Elsa.Activities.UnitTests/HTTP/SendHttpRequestTests.cs

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

* Small suggestions from copilot

* Update test/unit/Elsa.Activities.UnitTests/HTTP/SendHttpRequestTests.cs

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

* small copilot suggestion

* Introduce Scheduler Strategy Interfaces and Implementations for Workflow and Activity Execution Contexts (#6984)

* Introduce Scheduler Strategy Interfaces and Implementations for Workflow and Activity Execution Contexts

- Added `IWorkflowExecutionContextSchedulerStrategy` and `IActivityExecutionContextSchedulerStrategy` interfaces.
- Implemented `WorkflowExecutionContextSchedulerStrategy` and `ActivityExecutionContextSchedulerStrategy` for scheduling activities in workflows.
- Refactored scheduling logic to utilize the new scheduler strategies.
- Updated unit tests and test helpers to reflect refactoring, introducing fake implementations for testing purposes.
- Adjusted background execution scheduling and improved extensibility for custom scheduler strategies.

* Refactor `SendHttpRequestTests`: simplify scheduling assertions, use shared extensions, and standardize method naming. Streamline helper methods and remove unused test logic.

* Refactor: Replace `ActivityTestHelper` with `ActivityTestFixture` in unit tests for streamlined activity testing

- Introduced `ActivityTestFixture` with a fluent API for better test setup and execution of activities.
- Added extension methods `ActivityTestFixtureExtensions` and `ActivityTestFixtureHttpExtensions` for configuring attributes and HTTP services.
- Updated test guidelines and unit tests to use the new fixture and extensions.
- Removed `ActivityTestHelper`.

* Refactor: Move `ActivityTestFixture` and related extensions to shared project for reuse across test suites

- Consolidated `ActivityTestFixture`, `ActivityTestFixtureExtensions`, and `ActivityTestFixtureHttpExtensions` into `Elsa.Testing.Shared`.
- Updated namespaces and imports across unit tests to reflect new structure.
- Enhanced `AssertActivityAttributes` and added fluent configuration APIs.
- Adjusted `Directory.Packages.props` with new dependencies, including `NSubstitute` and `xunit.assert`.

* Refactor `SetVariableTests`: inline `ActivityTestFixture` initialization to simplify test setup.

* Refactor `ActivityTestFixture`: eliminate redundant field `_services`, add `UsedImplicitly` attributes, and improve service collection management

* Apply suggestion from @Copilot

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

* Add XML documentation for `ActivityExecutionContextExtensions`, detailing methods and parameters.

* Apply suggestion from @Copilot

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

* Add XML documentation for scheduler strategies and their methods

- Updated `IActivityExecutionContextSchedulerStrategy` and `IWorkflowExecutionContextSchedulerStrategy` interfaces with XML summaries for methods.
- Added XML documentation to implementations (`ActivityExecutionContextSchedulerStrategy`, `WorkflowExecutionContextSchedulerStrategy`) and test fakes for clarity.

* Refactor `WriteLineTests`: consolidate duplicate test logic, simplify setup with shared helper method, and enhance readability in assertions.

* Refactor `WriteLineTests` and `SetVariableTests`: replace `WriteLineAsync` assertions with synchronous `WriteLine`, streamline exception recording in `SetVariableTests`, and remove unused imports.

* Add `ParallelTests` for unit and integration testing with various scenarios (#6988)

- Added unit tests for `Parallel` activity to ensure proper scheduling of child activities, including empty and mixed activity cases.
- Added integration tests to validate execution flow and edge cases for `Parallel` activities (e.g., nested parallelism, fault handling).
- Enhanced `ScheduleChildrenAsync` in `Parallel` to handle no activity scenario by completing immediately.

---------

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

* Add new unit and integration tests for activity input and expression evaluation (#6990)

* Introduce Scheduler Strategy Interfaces and Implementations for Workflow and Activity Execution Contexts

- Added `IWorkflowExecutionContextSchedulerStrategy` and `IActivityExecutionContextSchedulerStrategy` interfaces.
- Implemented `WorkflowExecutionContextSchedulerStrategy` and `ActivityExecutionContextSchedulerStrategy` for scheduling activities in workflows.
- Refactored scheduling logic to utilize the new scheduler strategies.
- Updated unit tests and test helpers to reflect refactoring, introducing fake implementations for testing purposes.
- Adjusted background execution scheduling and improved extensibility for custom scheduler strategies.

* Refactor `SendHttpRequestTests`: simplify scheduling assertions, use shared extensions, and standardize method naming. Streamline helper methods and remove unused test logic.

* Refactor: Replace `ActivityTestHelper` with `ActivityTestFixture` in unit tests for streamlined activity testing

- Introduced `ActivityTestFixture` with a fluent API for better test setup and execution of activities.
- Added extension methods `ActivityTestFixtureExtensions` and `ActivityTestFixtureHttpExtensions` for configuring attributes and HTTP services.
- Updated test guidelines and unit tests to use the new fixture and extensions.
- Removed `ActivityTestHelper`.

* Refactor: Move `ActivityTestFixture` and related extensions to shared project for reuse across test suites

- Consolidated `ActivityTestFixture`, `ActivityTestFixtureExtensions`, and `ActivityTestFixtureHttpExtensions` into `Elsa.Testing.Shared`.
- Updated namespaces and imports across unit tests to reflect new structure.
- Enhanced `AssertActivityAttributes` and added fluent configuration APIs.
- Adjusted `Directory.Packages.props` with new dependencies, including `NSubstitute` and `xunit.assert`.

* Refactor `SetVariableTests`: inline `ActivityTestFixture` initialization to simplify test setup.

* Refactor `ActivityTestFixture`: eliminate redundant field `_services`, add `UsedImplicitly` attributes, and improve service collection management

* Apply suggestion from @Copilot

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

* Add XML documentation for `ActivityExecutionContextExtensions`, detailing methods and parameters.

* Apply suggestion from @Copilot

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

* Add XML documentation for scheduler strategies and their methods

- Updated `IActivityExecutionContextSchedulerStrategy` and `IWorkflowExecutionContextSchedulerStrategy` interfaces with XML summaries for methods.
- Added XML documentation to implementations (`ActivityExecutionContextSchedulerStrategy`, `WorkflowExecutionContextSchedulerStrategy`) and test fakes for clarity.

* Refactor `WriteLineTests`: consolidate duplicate test logic, simplify setup with shared helper method, and enhance readability in assertions.

* Refactor `WriteLineTests` and `SetVariableTests`: replace `WriteLineAsync` assertions with synchronous `WriteLine`, streamline exception recording in `SetVariableTests`, and remove unused imports.

* Add new unit and integration tests for activity input and expression evaluation

- Introduced comprehensive test suites covering activity input evaluation, expression handling, and fault scenarios.
- Added unit tests for `ExpressionDescriptorRegistry`, `ExpressionEvaluator`, and activity execution context extensions.
- Added integration tests: `CustomInputEvaluatorTests`, `InputEvaluationErrorTests`, and `InputPropertyEvaluationTests`.
- Enhanced code coverage for edge cases and async evaluation logic.

* Remove unused `RunWorkflowAsync` extension method from `RunActivityExtensions`.

* Rename `CustomInputEvaluatorTests` to `InputEvaluationTests` for consistency with naming conventions.

* Remove unused `Elsa.Workflows.Activities` import from `RunActivityExtensions`.

* Remove redundant comments from `InputEvaluationErrorTests` for clarity.

* Refactor unit tests to streamline activity and expression evaluations

- Refactored `ExecuteActivityAsync` and `ExecuteWriteLineAsync` into shared helpers for consistency and reuse across tests.
- Replaced redundant mock setups with helper methods in `ExpressionDescriptorRegistryTests`.
- Simplified test setup for expression and activity evaluation by removing unused imports and consolidating configuration logic.
- Enhanced readability by reducing duplicate code and leveraging shared utility methods.

* Refactor activity input evaluation tests

- Extracted `CreateContextAsync` helper into `EvaluationTestHelpers` for reuse across evaluation test suites.
- Replaced inline activity context setup with shared helper in `InputPropertyEvaluationTests`, `WrappedInputEvaluationTests`, and related test suites.
- Simplified test method names for clarity and consistency.
- Updated test annotations to enhance readability and align with naming conventions.

* Remove redundant test cases and unused imports

- Deleted duplicated and non-essential test cases across evaluation test suites.
- Removed unused imports to improve code cleanliness and readability.
- Streamlined variable initializations and method calls within test setups.

* Remove redundant test case from `InputEvaluationErrorTests`

- Deleted the `ContinuesEvaluationForMultipleInputs` test, as it overlaps with existing tests and does not provide additional coverage.

* Remove redundant assertion from `InputPropertyEvaluationTests`

- Deleted `Assert.True(context.GetHasEvaluatedProperties())`, as it is unnecessary for verifying test outcomes.

* Remove redundant test cases from `WrappedInputEvaluationTests`

- Deleted `UsesDefaultValueWhenInputIsNull` and `EvaluatesExpression` tests as they are either duplicated or unnecessary for current test coverage.

* Add unit test projects for `Elsa.Workflows.Management` and `Elsa.Expressions`

- Introduced new test projects to separate and organize unit tests for `Elsa.Workflows.Management` and `Elsa.Expressions`.
- Updated `Elsa.sln` to include references to the newly added test projects.
- Adjusted namespaces in affected test classes for consistency with the updated project structure.

* Refactor `ExpressionEvaluatorTests` for clarity and consistency

- Simplified test method names and annotations for improved readability.
- Replaced duplicate mock setups with helper functions (`CreateContextAsync`, `CreateContextWithMockHandlerAsync`, and related methods).
- Streamlined test setups by removing redundant code and consolidating context creation logic.
- Updated test annotations to include descriptive `DisplayName` attributes.

* Apply suggestion from @Copilot

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

* Remove redundant comment from `ExpressionEvaluatorTests` for clarity

* Remove redundant blank lines from unit test classes

- Eliminated unnecessary blank lines across `ActivityExecutionContextExtensions` test suites to improve code readability and consistency.

* Update src/modules/Elsa.Expressions/Services/ExpressionEvaluator.cs

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

* Expand `test-guidelines.md` with testing best practices, helper references, and example snippets

- Added detailed guidance on test project organization, updated helper documentation, and streamlined example code for activity unit testing.
- Introduced scheduler strategy information and integration test patterns for deterministic tests.
- Clarified usage of shared infrastructure like `ActivityTestFixture` and `AsyncWorkflowRunner`.

---------

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

---------

Co-authored-by: lucas.hipolito <lukhipolito@yahoo.com.br>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>
2025-10-20 20:11:46 +02:00
lucas.hipolito e22ecf83a0 Merge branch 'develop/3.6.0' into feat/test-guidelines 2025-10-09 14:02:08 +02:00
lucas.hipolito 2fde7ef048 Merge branch 'develop/3.6.0' into feature/unit-test-suite 2025-10-08 09:07:53 +02:00
Sipke Schoorstra fe4d74189a
Add coverage enforcement for test projects (#6950)
* Add coverage enforcement for test projects

* Expand GitHub Actions triggers to include additional branch patterns

* Update `coverlet.msbuild` configuration and centralize dependency version management

- Removed inline version specification for `coverlet.msbuild` in `test/Directory.Build.props`.
- Centralized `coverlet.msbuild` version definition in `Directory.Packages.props` for consistency and maintainability.

* Remove `Elsa.Common.Core` unit test project and related test files

* Add Directory.Build.props for test project organization and update property configurations

- Introduced `Directory.Build.props` files for `test/unit` and `test/integration` to define project-specific properties.
- Updated `test/Directory.Build.props` to include new coverage formats and an exclusion for `Elsa.Testing.Shared`.
- Adjusted solution file to link new `Directory.Build.props` files.
- Configured threshold properties for `unit`, `integration`, and `component` test directories.

* Disable coverage collection for performance tests in project file

* Expand GitHub Actions workflow triggers and add PR-specific condition for test job
2025-10-07 19:59:53 +02:00
lucas.hipolito 4a26819ed7 (WIP) Initial context helper + provisional unit tests for setvariable 2025-10-07 15:56:08 +02:00
lucas.hipolito 9ac605fbb5 Renaming guideline file 2025-10-07 09:03:16 +02:00
lucas.hipolito 3d9cefa894 Better and revised general testing guidelines 2025-10-06 17:54:11 +02:00
lucas.hipolito 4d17f869a3 Merge branch 'develop/3.6.0' into feat/test-guidelines 2025-10-06 13:45:41 +02:00
Sipke Schoorstra eb7a76a8c0
Refactor flowchart token handling and enhance merge mode behavior (#6937)
* Refactor flowchart token handling and enhance merge mode behavior

- Improve token emission, consumption, and scheduling logic.
- Add support for distinct merge modes: None, Converge, Stream, and Race.
- Update `MergeMode` enum documentation to clarify behavior.
- Adjust default merge mode from `Converge` to `None`.

* Add integration tests for implicit join behaviors with None and Converge merge modes

- Added workflows `fork-decision-join-none.json` and `fork-decision-join-converge.json` to test scenarios.
- Implemented `ForkDecisionJoinTests` to validate execution logic based on merge modes.
- Updated project file to include new workflows for testing.

* Refactor `ImplicitJoins` tests to `JoinBehaviors` and add test for `WaitAll` join mode

- Renamed `ImplicitJoins` test namespace and workflows to `JoinBehaviors`.
- Added `fork-decision-join-waitall.json` workflow to test the `WaitAll` merge mode.
- Refactored `ForkDecisionJoinTests` with reusable logic for execution and assertions.
- Updated project file to include the new workflow for testing.

* Refactor flowchart token handling for improved clarity and efficiency

- Simplified token consumption and filtering logic.
- Removed default port fallback for active outbound connections.
- Improved readability and maintainability of token handling in merge mode scenarios.

* Refactor tests and workflows for `JoinBehaviors`

- Transitioned connections to inline object initializers for simplicity.
- Updated workflow paths in `ParallelJoinCompletesTests` and `JoinRunsOnceTests` to match `JoinBehaviors`.
- Adjusted connection definitions in `ImplicitLoopWorkflow` for consistency.

* Format JSON workflow files

* Add ADR for explicit merge modes in flowchart joins

- Introduced `MergeMode` enum with modes: None, Converge, Stream, and Race.
- Documented motivation, decision, and implementation details.
- Updated solution to include new ADR file.
2025-10-01 15:01:33 +02:00
lucas.hipolito 4d78197c80 Moving integrators instructions to another doc 2025-09-30 08:59:44 +02:00
lucas.hipolito 260680f3a2 Renaming test guideline 2025-09-29 19:55:30 +02:00
lucas.hipolito a4e830ac54 Reverting some changes for 3.6.0 compatibility 2025-09-29 09:49:37 +02:00
lucas.hipolito f483dbe14a Merge branch 'develop/3.6.0' into feat/test-guidelines 2025-09-29 09:11:36 +02:00
Sipke Schoorstra d56e9cd852
Add integration tests for migration in Elsa.Alterations module
- Created a new `Elsa.Alterations.IntegrationTests` project.
- Added `MigrationTests` to validate workflows migration from version 1 to 2.
- Updated solution file to include the new integration tests project.
2025-09-28 20:44:55 +02:00
Sipke Schoorstra ff1f0833ad
Restore EF Core persistence layer (#6931)
* Restore EF Core persistence layer

Originally, we had moved EF Core to the extensions repo, but in practice this turned out to be rather impractical when debugging elsa-core, given that we would lose all of the state (workflow definitions, instances, etc.) across application restarts.

* Integrate PostgreSQL support into EF Core persistence and enhance BlobStorage workflows provider setup.
2025-09-27 20:39:18 +02:00
Sipke Schoorstra 1bf51d7f82
Remove unused docker-compose-datadog+otel-collector.yml reference from solution file. 2025-09-25 22:52:19 +02:00
Sipke Schoorstra f24b4394cf
Add WorkflowStateCommitted notification support and update state handling logic
- Introduced `WorkflowStateCommitted` notification to encapsulate workflow execution context, state, and instance details.
- Updated `DefaultCommitStateHandler` to publish `WorkflowStateCommitted` via `IMediator`.
- Adjusted `DispatchWorkflowExtensions` to use `WorkflowStateCommitted` for workflow completion.

Updates KubernetesClient and Microsoft packages (#6917)

* Remove Proto.Cluster.Kubernetes dependency due to vulnerability

- Temporarily removed `Proto.Cluster.Kubernetes` package and provider integration because of a vulnerability in its dependency (https://avd.aquasec.com/nvd/2025/cve-2025-9708).
- Adjusted related cluster provider and remote configuration logic.
- Updated `PortAttribute` default parameter for clarity.

* Revert "Remove Proto.Cluster.Kubernetes dependency due to vulnerability"

This reverts commit 0720d970968e4f7338825407258b34ddffb1d2a4.

* Add KubernetesClient package and update MicrosoftVersion to 9.0.9

- Added `KubernetesClient` package to the project dependencies.
- Updated `MicrosoftVersion` to `9.0.9` in `Directory.Packages.props`.
Update Polly packages

- Bump Polly and Polly.Extensions package versions to 8.6.3.

Update `Microsoft.AspNetCore.Authorization` to use `MicrosoftVersion` property

Ensure Docker images ship CA trust and add TLS smoke tests (#6918)

Remove TlsSmoke project and related solution references

- Deleted `TlsSmoke` project files (`Program.cs` and `TlsSmoke.csproj`).
- Removed `TlsSmoke` project reference from the solution file (`Elsa.sln`).

Add comprehensive Copilot coding agent instructions for repository onboarding (#6920)

* Initial plan

* Add comprehensive .github/copilot-instructions.md with validated build instructions

Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sfmskywalker <938393+sfmskywalker@users.noreply.github.com>
Add ForEach tests, introduce asynchronous workflow runner and enhance workflow events. (#6926)

* Introduce asynchronous workflow runner and enhance workflow events.

- Added `AsyncWorkflowRunner` to enable asynchronous workflow execution and result tracking.
- Introduced new event arguments, such as `ActivityExecutedEventArgs` and `WorkflowStateCommittedEventArgs`.
- Expanded `WorkflowEvents` class to include `ActivityExecuted`, `ActivityExecutedLogUpdated`, and `WorkflowStateCommitted` events.
- Refactored event arguments into the `Elsa.Testing.Shared.EventArgs` namespace.
- Enhanced tests with `AsyncWorkflowRunner` and new event-driven workflow scenarios.

* Refactor event argument classes to unify namespace and simplify inheritance

* Add shared component DotSettings file to support namespace exclusions
Refactor `WaitAsync` call in `DispatchWorkflowsTests` to remove unnecessary generic type.
2025-09-25 20:58:21 +02:00
lucas.hipolito 32f6a393a2 WIP: initial docs dump 2025-09-25 12:58:31 +02:00
Sipke Schoorstra 67fb43e0ba
Remove TlsSmoke project and related solution references
- Deleted `TlsSmoke` project files (`Program.cs` and `TlsSmoke.csproj`).
- Removed `TlsSmoke` project reference from the solution file (`Elsa.sln`).
2025-09-19 12:07:13 +02:00
Sipke Schoorstra 525f21bcc8
Merge remote-tracking branch 'origin/patch/3.5.1' into develop/3.6.0 2025-09-15 18:46:48 +02:00
Sipke Schoorstra 0ef6e16882
Removes Elsa Logging modules from solution
Removes the Elsa Logging modules and related configurations from the solution file.
These modules are likely being removed or reorganized as part of a larger refactoring effort.
2025-09-13 13:31:33 +02: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 8645493b04
Introduces modular logging framework (#6872)
* Initial implementation of log activity + base sink

* Refactor logging implementation: replace `Elsa.ProcessLogging` with a new modular `Elsa.Logging` framework, introducing support for configurable log sinks, enhanced logging extensibility, and updated dependencies in consuming projects.

* Enhance logging framework: introduce custom `NullableBoolConverter` and update JSON serialization/deserialization logic for log sink handling.

* Update description for `Log` activity input: clarify target sinks configuration

* Set default value of `SinkNames` input in `Log` activity to non-nullable collection

* Set `DisplayName` for `Sinks` input in `Log` activity

* Refactor logging framework: update `ILogSink` and `ILogSinkRouter` to support arguments and attributes, enhance `Log` activity to use updated interfaces, and add default category handling.

* Refactor logging framework: simplify argument handling in `ILogSink` and `ILogSinkRouter`, update `Log` activity inputs, and improve message formatting in `MelLogSink`.

* Update logging framework to simplify log sink creation, enhance category filtering, and refactor `ILogSink`/`ILogSinkRouter` interface methods.

* Introduce modular logging framework enhancements: add `Console` and `Serilog` logging features, refactor `ILogSink` framework, and update projects to align with a modular architecture.

* Refactor logging framework: introduce `AddCategoryFilters` extension, replace `DefaultCategory` handling with enhanced category filters, and update sink creation logic for consistency.

* Refactor logging framework: rename `SinkOptions` to `LogSinkOptions`, standardize naming across log sink types, and update configuration and sink factory logic for consistency.

* Enhance logging framework: add `ConfigureDefaults` methods, update `ILogSinkCatalog` to use `IServiceScopeFactory`, and improve logging configuration handling and defaults setup.

* Introduce asynchronous log entry processing: add `ILogEntryQueue`, `LogEntryBackgroundWorker`, and related models to enable queue-based logging and background processing. Update `Log` activity to enqueue log entries for processing.

* Add unit and integration tests for `Elsa.Logging.Core` library, refactor logger setup in `Elsa.Server.Web`, enhance logging configuration, and standardize `Directory.Packages.props` file.

* Apply suggestion from @Copilot

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

* Add documentation comments to logging framework classes, interfaces, methods, and factories to enhance code readability and maintainability. Remove unused `CustomPurpleConsoleFormatter` class and `logs` folder from server project.

* Apply suggestion from @Copilot

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

* Make `LogEntryInstruction` and `LogEntryQueue` classes public and simplify return statement in `LogSinkCatalog.ListAsync` method.

* Standardize terminology in `ILogSink` interface and `LoggerSink` implementation: rename `properties` to `attributes`. Update project files and solution structure to reflect integration test additions.

* Apply suggestion from @Copilot

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

* Apply suggestion from @Copilot

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

* Update documentation comments in `LoggingFeature` and `LogEntryInstruction` to clarify functionality and improve precision.

* Add README for `Elsa.Logging` module with configuration examples, usage details, and extension guidance.

* Add `Dictionary` UI hint to `InputUIHints` and update `Attributes` in `Log` activity to use it.

* Update `Log` activity default category to "Process", add integration tests for logging, and enhance null safety in `ConfigurationLogSinkProvider`.

* Remove `UseLoggingFramework` middleware from `Program.cs` to streamline workflow initialization.

---------

Co-authored-by: lucas.hipolito <lukhipolito@yahoo.com.br>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-25 09:55:27 +02:00
Sipke Schoorstra bc3543fcb6
Merge 3.5.0 2025-08-06 20:40:27 +02:00
Sipke Schoorstra 133e8dfc63
Introduce TenantDeleted event to handle tenant cleanup (#6843)
* Introduce `TenantDeleted` event to handle tenant cleanup

Added a `TenantDeleted` event to differentiate between tenant deactivation and deletion. Updated event handlers and services to support unregistering resources only during tenant deletion, ensuring clearer separation of responsibilities. Included ADR documentation for the new event.

* Remove unnecessary blank line in tenant deactivation logic
2025-08-06 08:43:39 +02:00