Skip to content

Helm and K8s Commands#12

Merged
thomhurst merged 11 commits into
mainfrom
feature/helm-and-k8s-commands
Jul 6, 2023
Merged

Helm and K8s Commands#12
thomhurst merged 11 commits into
mainfrom
feature/helm-and-k8s-commands

Conversation

@thomhurst

Copy link
Copy Markdown
Owner

No description provided.

@thomhurst
thomhurst temporarily deployed to Pull Requests July 6, 2023 20:11 — with GitHub Actions Inactive
@thomhurst
thomhurst merged commit 5cb79e3 into main Jul 6, 2023
@thomhurst
thomhurst deleted the feature/helm-and-k8s-commands branch August 17, 2023 09:10
@claude claude Bot mentioned this pull request Feb 22, 2026
8 tasks
thomhurst added a commit that referenced this pull request Feb 22, 2026
- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException
thomhurst added a commit that referenced this pull request Jul 21, 2026
- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException
thomhurst added a commit that referenced this pull request Jul 21, 2026
- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException
thomhurst added a commit that referenced this pull request Jul 21, 2026
- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException
thomhurst added a commit that referenced this pull request Jul 21, 2026
- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException
thomhurst added a commit that referenced this pull request Jul 21, 2026
- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException
thomhurst added a commit that referenced this pull request Jul 21, 2026
* feat: Add distributed workers mode with artifact sharing

Introduces a distributed execution mode where pipeline instances coordinate
across multiple runners (e.g., GitHub Actions matrix). Instance 0 becomes the
master orchestrating work, while additional instances act as workers.

Key components:
- Core abstractions: IDistributedCoordinator, IDistributedArtifactStore
- Redis coordinator backend for cross-instance orchestration
- S3-compatible artifact store (supports Cloudflare R2, AWS S3, MinIO)
- Attribute-driven artifact sharing ([ProducesArtifact], [ConsumesArtifact])
- Automatic deduplication of artifact downloads for same paths
- Matrix module expansion and capability-based routing
- Worker health monitoring and cancellation propagation

Includes 86+ unit tests across distributed, Redis, and S3 test projects.

* fix: Add missing Artifacts files excluded by .gitignore

The artifacts/ gitignore rule was case-insensitively matching our
source Artifacts/ directories. Added exceptions for src/**/Artifacts/
and test/**/Artifacts/ to allow these to be tracked.

* feat: Move solution builds into BuildSolutionsModule with artifact sharing

Replace per-instance build step with a single BuildSolutionsModule that
runs on the master Linux instance, stages bin/Release/ output into
_build-staging/, and shares it to workers via the distributed artifact
store. Workers now only restore (for project.assets.json) and receive
compiled output via ConsumesArtifact before running tests.

* fix: Address code review feedback on distributed workers

- Replace reflection-based CompletionSource access with IModule.ResultTask
  property, eliminating fragile reflection in WorkerModuleExecutor
- Remove BuildServiceProvider() anti-pattern in DistributedPipelinePlugin;
  resolve options directly from service descriptors instead
- Implement WorkerHealthMonitor heartbeat tracking with actual timeout
  detection via GetLastHeartbeatAsync/UpdateWorkerStatusAsync on coordinator
- Fix capability dequeue livelock: InMemoryDistributedCoordinator now uses
  List+SemaphoreSlim with selective dequeue instead of Channel re-enqueue
- Redis dequeue uses LRANGE+LREM for capability scanning and BRPOP for
  blocking wait, eliminating polling loops
- Propagate CancellationToken via IHostApplicationLifetime in worker
  executor instead of using CancellationToken.None everywhere
- Stream S3 artifact downloads to temp files instead of MemoryStream to
  avoid OOM on large artifacts
- Use strategy.job-total for TOTAL_INSTANCES in GitHub Actions workflow
- Fix ResolvePathPattern to return all matched paths instead of collapsing
  to common parent directory
- Remove superseded docs/specs planning artifacts

* fix: Remove analyzers build step and make BuildSolutionsModule deps optional

Move ModularPipelines.Analyzers.sln into the restore loop and
BuildSolutionsModule instead of a separate workflow build step.
Make DependsOn<BuildSolutionsModule> optional since it has
[RunOnLinuxOnly] and isn't registered on Mac/Windows instances.

* fix: Address round 3 code review feedback

- Fix WorkerModuleExecutor deadlock: inject IModuleRunner and execute
  modules through the framework's execution pipeline instead of awaiting
  a CompletionSource that nothing sets. Add WorkerModuleScheduler.
- Fix Redis dequeue BRPOP bounce: replace BRPOP+LPUSH fallback with
  Task.Delay polling since LRANGE scan handles capability matching.
- Remove broken IArtifactContext singleton (empty moduleTypeName).
- Fix _pluginRegistered thread safety with Interlocked.CompareExchange.
- Remove duplicate AddDistributedMode from core PipelineBuilderExtensions
  (didn't register plugin). Use ModularPipelines.Distributed.Extensions
  in Program.cs.

* fix: Activate distributed mode by fixing plugin service ordering

The DistributedPipelinePlugin.ConfigureServices ran before user-registered
services were added to the host service collection. This meant
IOptions<DistributedOptions> was never found, and the plugin returned early
without replacing IModuleExecutor. All CI instances ran in standard mode.

Fix: Move user service registration before plugin services in
PipelineBuilder.BuildPipelineAsync so plugins can inspect user config.

Also add Microsoft.Testing.Extensions.HangDump to the 3 distributed test
projects so RunUnitTestsModule's --hangdump flag is recognized.

* refactor: Merge distributed execution into core ModularPipelines package

Move all 22 implementation files from ModularPipelines.Distributed into
ModularPipelines/Distributed/ subdirectories. Distributed infrastructure
(coordinator, artifact store, serialization) is now always registered with
in-memory defaults via DependencyInjectionSetup. When AddDistributedMode()
is called with TotalInstances > 1, PipelineBuilder conditionally replaces
the executor based on role — no plugin ceremony needed.

- Delete ModularPipelines.Distributed project entirely
- Remove plugin-based service registration (DistributedPipelinePlugin)
- Add RegisterDistributedServices() to DependencyInjectionSetup
- Add ActivateDistributedModeIfConfigured() to PipelineBuilder
- Simplify DistributedPipelineBuilderExtensions (no plugin registration)
- Remove Distributed ProjectReference from Redis, S3, and test projects

* fix: Update Redis dequeue tests to match scan-based implementation

The DequeueModuleAsync implementation uses ListRangeAsync (scan) +
ListRemoveAsync (atomic remove), but three tests still mocked the old
ListRightPopAsync API. The unmocked ListRangeAsync returned an empty
array, causing an infinite polling loop that hung the test runner.

* feat: Replace polling with pub/sub, strip heartbeats, add completion signal

- Replace Redis LRANGE polling with pub/sub notifications for dequeue,
  reducing commands from ~100K+/hour to ~520 per pipeline run
- Remove heartbeat, cancellation monitoring, and worker health systems
  (not needed; GitHub Actions handles runner failures)
- Add SignalCompletionAsync to IDistributedCoordinator so workers exit
  cleanly when the master finishes distributing all work
- Simplify WorkerRegistration, DistributedOptions, and coordinator interfaces

* fix: Remove ModularPipelines.Distributed from build project list

The project was merged into core and no longer exists as a separate package.

* fix: Address round 7 code review feedback

- Apply distributed results back to module CompletionSource via reflection
- Link DistributedModuleExecutor CTS to host ApplicationStopping token
- Forward per-module timeout/alwaysRun config to ModuleAssignmentConfig
- Fix artifact upload OOM risk by using temp files instead of MemoryStream
- Delete empty DistributedSummaryAggregator placeholder
- Fix Upstash Redis TLS port (6379 -> 6380)
- Add TODO remarks on unconnected MatrixModuleExpander
- Remove [PinToMaster] attributes from build modules

* fix: Revert Upstash Redis port to 6379 (TLS via ssl=True flag)

Upstash uses port 6379 with ssl=True in StackExchange.Redis, not 6380.
The review suggestion was incorrect.

* fix: Address round 9 code review items #2, #3, #10, #11, #12

- Wrap worker PublishResultAsync in try/catch to prevent master deadlock
- Fix thread-safety of completed flag in Redis DequeueModuleAsync using Volatile
- Share single IConnectionMultiplexer across Redis coordinator and artifact factories
- Fix Lazy<Task> capturing first caller's CancellationToken in artifact deduplication
- Add exception filter to S3 catch blocks to not swallow OperationCanceledException

* fix: Activate distributed mode by using standard Options pattern

AddDistributedMode was using AddSingleton(Options.Create(options)) which
registered as OptionsWrapper<T> not IOptions<T>. ResolveDistributedOptions
never found the registration, so distributed mode never activated.

Switched to services.Configure<DistributedOptions>() which follows the
standard .NET Options pattern and is correctly resolved by the existing
IConfigureOptions<T> fallback path in ResolveDistributedOptions.

* fix: Disable payload signing for R2/S3-compatible artifact uploads

Cloudflare R2 does not support STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER
signing used by newer AWS SDK versions. Set DisablePayloadSigning = true
on PutObjectRequests to use standard signing instead.

* fix: Remove S3 object tags (R2 unsupported) and fail fast on artifact upload errors

- Remove TagSet from PutObjectRequest — Cloudflare R2 rejects x-amz-tagging
  header. Tag metadata was redundant with the JSON sidecar object.
- Stop swallowing artifact upload exceptions in DistributedModuleExecutor so
  the pipeline fails immediately instead of hanging waiting for worker results.

* fix: Signal workers to stop when master crashes

Move SignalCompletionAsync into the finally block so workers are always
notified to shut down, even when the master fails with an exception.
Previously workers would hang forever waiting for work that never comes.

* fix: Cascade worker failures to master for fast pipeline termination

- Master cancels the pipeline CTS when any distributed module fails,
  stopping all pending work and signaling workers to shut down.
- Worker artifact download failures now propagate instead of being
  swallowed — no point running a module if its dependencies are missing.
- Worker failure results use properly-typed ModuleResultFactory.CreateException
  instead of non-generic ModuleResult.CreateFailure, fixing the
  ArgumentException that prevented publishing failure results to master.

* fix: Prevent artifact race condition and harden worker failure handling

- Fix race condition where scheduler released dependent modules before
  artifact upload completed. PinToMaster modules now execute with a
  no-op scheduler, upload artifacts, then mark complete on real scheduler.
- Move worker artifact download inside inner try block so failures
  publish properly-typed results back to master.
- Add null safety for S3 ListObjectsV2 response (R2 returns null).

* fix: Register distributed module results so pipeline status reflects failures

DistributedModuleExecutor now registers results in IModuleResultRegistry
for all distributed modules — success, failure, and cancellation paths.
Previously, PipelineSummary.GetStatus() treated unregistered modules as
successful, causing the pipeline to report green even when workers failed.

Adds 15 unit tests covering result registration, fail-fast cascade,
race condition prevention (no-op scheduler for PinToMaster), and
completion signaling.

* fix: Add worker readiness barrier and fix flaky hook tests

Master now waits for workers to register before distributing work,
preventing fast workers from consuming all items before slow-booting
workers (e.g., Windows/macOS) come online. Uses CapabilityTimeoutSeconds
as backstop. Also marks DirectModuleHooksIntegrationTests as
[NotInParallel] to fix static ExecutionLog race condition.

* fix: Require linux capability for RunUnitTestsModule

BuildSolutionsModule runs on master (Linux) and produces Linux binaries.
RunUnitTestsModule uses --no-build, so it must run on the same OS.
Without this, it could be distributed to Windows/macOS workers where
the Linux-built binaries don't exist.

* fix: Allow empty BranchName in detached HEAD (CI merge ref checkout)

* fix: Pin modules that use GetModule<T>() to master to prevent cross-process hang

PackagePathsParserModule and FindProjectDependenciesModule call
context.GetModule<T>() which waits on the target module's CompletionSource.
In distributed mode, CompletionSource is only set in the process that
executed the module, so these calls hang forever on workers. Adding
[PinToMaster] ensures they always run on the master alongside their
dependencies.

* Revert "fix: Pin modules that use GetModule<T>() to master to prevent cross-process hang"

This reverts commit 945d176.

* feat: Add dependency result propagation and SignalR coordinator for distributed mode

Phase 1 - Core fix: Workers now receive dependency results in ModuleAssignment,
enabling cross-process GetModule<T>() resolution without PinToMaster workaround.

Phase 2 - New SignalR-based coordinator package for direct master<->worker
communication without Redis dependency.

Phase 3 - Redis discovery package for cross-network master URL advertisement.

* fix: Cap dependency result size to prevent Redis payload overflow

Large module results (e.g., BuildSolutionsModule ~14MB) bundled as
dependency results in ModuleAssignment exceeded Upstash Redis 10MB
request limit. Now strips Value to null for results over 256KB while
preserving metadata, so GetModule<T>() still resolves as a barrier.

* fix: Use GZip compression instead of stripping for large dependency results

Stripping the Value to null broke modules that actually read dependency
results (e.g., PackagePathsParserModule reads PackProjectsModule output).
Now GZip-compresses dependency results exceeding 64KB (text output
compresses ~10:1), preserving full values while staying under Redis 10MB
request limit. Workers decompress before deserialization.

* fix: Clear distributed env vars from test subprocesses to prevent hang

RunUnitTestsModule spawns test processes that inherit the worker's
environment variables (INSTANCE_INDEX, TOTAL_INSTANCES, Redis and R2
credentials). Clear these to prevent any interference with test
execution on distributed workers.

* fix: Add JSON converters for File and Folder to enable safe cross-process serialization

File and Folder objects crash during JSON ser/deser when the underlying
path doesn't exist on the current machine (e.g., Windows path on Linux).
System.Text.Json calls property getters (Length, Attributes) which
access the filesystem and throw FileNotFoundException.

Add FilePathJsonConverter and apply [JsonConverter] at the class level
on both File and Folder so they serialize as path strings only. This
enables distributed workers to safely pass File/Folder results across
processes without pinning modules to specific machines.

* perf: Split RunUnitTestsModule into per-project modules for distributed execution

The monolithic RunUnitTestsModule ran all 8 test projects on a single
worker, leaving other distributed workers idle for ~6 minutes. Split
into individual modules (one per test project) so the distributed
scheduler can assign them across workers in parallel.

- Add RunUnitTestModule abstract base class with shared test config
- Add 8 concrete modules, one per test project
- Add RunAllUnitTestsModule gate using DependsOnAllModulesInheritingFrom
- Update PackProjectsModule and UploadPackagesToNugetModule dependencies

* fix: Pin FindProjects modules to master to prevent cross-instance path mismatch

FindProjectsModule returns Sourcy compile-time absolute paths that are
machine-specific. When distributed to a worker, the master's
GenerateReadMeModule and FindProjectDependenciesModule fail trying to
open those worker-specific paths locally.

* Revert "fix: Pin FindProjects modules to master to prevent cross-instance path mismatch"

This reverts commit f552ec7.

* fix: Portable path serialization for cross-platform distributed mode

FindProjectsModule ran on Windows worker (D:/a/... paths) while master
ran on Linux. The File objects serialized with absolute Windows paths
which Linux couldn't resolve, causing GenerateReadMeModule to fail with
InvalidProjectFileException.

Fix: ModuleResultSerializer now uses portable path converters that
serialize File/Folder paths relative to the git root. On deserialization,
paths are resolved against the local git root, making them work across
any platform combination.

This eliminates the need for PinToMaster on path-dependent modules.

* refactor: Remove PinToMaster — master participates as worker via work queue

Delete [PinToMaster] attribute entirely. The master (instance 0) now
competes with external workers for assignments through the same work
queue, with routing based purely on capabilities.

- Add master worker loop to DistributedModuleExecutor that dequeues
  and executes modules concurrently alongside external workers
- Auto-detect OS capabilities from RunOn*Only attributes in
  DistributedWorkPublisher so [RunOnLinuxOnly] implies "linux" capability
- Implement DequeueModuleAsync in SignalRMasterCoordinator (was
  NotSupportedException since master never dequeued before)
- Remove [PinToMaster] from all 7 build modules
- Update tests: replace PinToMaster tests with master-as-worker tests,
  add NoDequeueCoordinator wrapper for distributed-path test isolation
- Update distributed mode documentation and architecture diagrams

* fix: Address 7 code review items for distributed mode robustness

- Remove reflection in ModuleCompletionSourceApplicator; add IModule.TrySetDistributedResult
- Wrap DI factory async calls in Task.Run to prevent sync-context deadlock
- Stream chunked upload without full MemoryStream buffering
- Atomic Redis dequeue via Lua script (eliminates LRANGE+LREM race)
- Publish failure result when worker can't resolve module (prevents master hang)
- Replace Task.Delay(500) with proper Kestrel StartAsync for SignalR server
- Add per-module timeout (ModuleResultTimeoutSeconds) to CollectDistributedResultAsync

* fix: Use SignalR for coordination, Redis only for discovery

Replace AddRedisDistributedCoordinator with AddSignalRDistributedCoordinator
+ AddRedisSignalRDiscovery. Redis was being used as the full coordinator,
meaning large serialized module results (14MB+) hit Upstash's 10MB limit.
Now Redis only advertises the master's SignalR URL; all coordination
(work queue, results, worker registration) flows over direct SignalR sockets.

* fix: Defer coordinator/artifact factory resolution to first use

Factory CreateAsync was called eagerly during DI build, causing workers
to block on master URL discovery before the master had started. Now
CreateAsync is deferred to the first actual coordinator method call,
by which time the master has advertised its SignalR URL via Redis.

* fix: Wire real SignalR hub context, consistent role detection, centralize capability matching

- Remove no-op proxy classes (BroadcastClientProxy, SingleClientProxy, MasterHubContextAdapter)
- Hub receives SignalRMasterState via constructor DI instead of property injection
- Factory uses real IHubContext from WebApplication DI container
- Add env var check to factory role detection (matches RoleDetector)
- Make CapabilityMatcher public with IReadOnlySet<string> overload
- Replace all inline IsSubsetOf checks with CapabilityMatcher.CanExecute (fixes case-sensitivity)

* feat: Add cloudflared tunnel for cross-VM SignalR connectivity

GitHub Actions matrix jobs run on separate VMs with no direct network
access. The master's localhost:5099 is unreachable from worker VMs.

- Add CloudflaredTunnel that starts a quick tunnel (no auth needed)
- Master starts tunnel after Kestrel binds, captures public HTTPS URL
- Advertises tunnel URL via Redis discovery instead of localhost
- Workers connect via the public tunnel URL
- CI workflow installs cloudflared on master instance

* fix: Retry worker connection for tunnel DNS propagation

Cloudflared quick tunnel URLs need time for DNS to propagate.
Workers now retry the initial connection with exponential backoff
within the connection timeout window, rebuilding HubConnection on
each attempt since it can't restart after failure.

* fix: Create fresh HubConnectionBuilder on each retry attempt

HubConnectionBuilder.Build() can only be called once. Extract
BuildHubConnection helper and create a new builder+connection
for each retry attempt. Dispose failed connections before retrying.

* fix: Match JSON serialization options between SignalR server and client

Server's JsonHubProtocol defaults to camelCase naming, but the client
uses default STJ options (PascalCase). This causes "Error binding
arguments" when deserializing WorkerRegistration records.

Configure server to use PascalCase (PropertyNamingPolicy = null) and
case-insensitive matching to align with the client.

* fix: Use CreateBuilder instead of CreateSlimBuilder for SignalR JSON serialization

CreateSlimBuilder in .NET 10 disables reflection-based JSON serialization,
which prevents IReadOnlySet<string> deserialization in SignalR hub method
binding (RegisterWorker). CreateBuilder restores full JSON support.

* fix: Scope Redis discovery by GITHUB_RUN_ID and match client JSON protocol

Two fixes:
1. Set RunIdentifier to GITHUB_RUN_ID so overlapping CI runs don't
   share stale master URLs in Redis.
2. Add matching AddJsonProtocol config to the client HubConnectionBuilder
   (PascalCase + case-insensitive) to match the server-side settings.

* fix: Use HashSet<string> instead of IReadOnlySet<string> in records for SignalR serialization

System.Text.Json cannot reliably deserialize IReadOnlySet<string> as a
record constructor parameter in SignalR's argument binding pipeline.
Using the concrete HashSet<string> type eliminates the binding error.

* test: Add SignalR integration tests for full serialization round-trip

Start a real SignalR server and client to validate RegisterWorker,
PublishResult, and ModuleAssignment serialization. Also resolve
AdvertisedUrl from actual bound port (supports port 0 for tests).

* test: Add multi-worker routing and end-to-end integration tests

Tests validate:
- Capability-based routing across 3 workers
- Result broadcast to non-producing workers (dependency propagation)
- Full workflow: enqueue → assign → execute → publish → collect → complete

* fix: Increase default connection timeout to 120s for DNS propagation

macOS CI runners take longer to resolve cloudflared tunnel DNS names.
30 seconds was insufficient — increase to 120s to accommodate slower
DNS resolution across different CI platforms.

* fix: Update default timeout test assertion and use null-object pattern for WorkerModuleScheduler

- ConfigurationTests: update expected ConnectionTimeoutSeconds from 30 to 120
  to match the default change in SignalRDistributedOptions
- WorkerModuleScheduler: return never-completing Channel reader instead of
  throwing NotSupportedException from ReadyModules property

* fix: Validate artifact size on chunked download to detect expired chunks

If Redis evicts individual chunk keys under memory pressure, the
download would silently return truncated data. Now validates the
reassembled length against the stored SizeBytes in ArtifactReference.

* fix: Address code review feedback — MatrixTarget, busy-poll, tunnel regex

- Make MatrixTargetAttribute internal (not yet wired to executor, avoid
  shipping dead public API)
- Replace 50ms busy-poll in SignalRMasterCoordinator.DequeueModuleAsync
  with SemaphoreSlim signal from EnqueueModuleAsync/SignalCompletionAsync
- Generalize cloudflared tunnel URL regex to support custom domains and
  add warning log when URL detection times out

* fix: Revert cloudflared regex to trycloudflare.com — broad regex matched www.cloudflare.com

The generalized regex `https://[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+` was too broad
and matched `https://www.cloudflare.com` from cloudflared's log output, causing
workers to connect to the Cloudflare homepage instead of the tunnel URL.

Reverted to `*.trycloudflare.com` since we only use quick tunnels.

* refactor: Address code review — volatile fields, O(1) lookup, deduplicate shared code, pin cloudflared

- Add volatile to DeferredCoordinator/DeferredArtifactStore _inner fields
  for correct double-checked locking memory visibility (#9)
- Replace O(n) FirstOrDefault module lookups with Dictionary<string, IModule>
  built once per execution in both executors (#4)
- Extract DependencyResultApplicator with shared ApplyDependencyResults and
  PublishResolutionFailureAsync, eliminating duplication between
  DistributedModuleExecutor and WorkerModuleExecutor (#5)
- Pin cloudflared to version 2026.2.0 in CI workflow instead of using
  latest release (#8)

* style: format distributed changes

* fix(distributed): use Redis REST discovery

CI provides Upstash REST credentials, so deriving TCP credentials made every runner fail. Isolate discovery keys by CI or Git revision and simplify flagged execution paths.

* fix(ci): handle unavailable Redis discovery

Probe the shared REST endpoint before enabling distributed mode so stale CI credentials degrade to standalone runners instead of crashing every matrix job.

* fix(ci): stop secondary fallback runners

When Redis discovery is unavailable, run the pipeline once on the primary Linux instance and let secondary matrix jobs exit successfully.

* fix(ci): run work on every matrix OS

Route real solution builds to Windows and macOS workers, and surface distributed fallback through visible GitHub warnings.

* fix(ci): preserve required check name

Keep the primary matrix job aligned with the protected branch status context while retaining distinct secondary names.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant