diff --git a/.github/workflows/next-gen-ci.yml b/.github/workflows/next-gen-ci.yml
new file mode 100644
index 0000000000..470cc40ca9
--- /dev/null
+++ b/.github/workflows/next-gen-ci.yml
@@ -0,0 +1,189 @@
+name: next-gen-ci
+
+on:
+ push:
+ branches: [ out-of-process-collection ]
+ paths:
+ - 'next-gen/**'
+ pull_request:
+ branches: [ out-of-process-collection ]
+ paths:
+ - 'next-gen/**'
+ workflow_dispatch:
+ inputs:
+ force_run:
+ description: 'Force run even if no next-gen changes'
+ required: false
+ default: 'false'
+
+env:
+ NUGET_PACKAGES: ${{ github.workspace }}/packages
+ DOTNET_CLI_TELEMETRY_OPTOUT: 1
+
+permissions:
+ contents: read
+
+jobs:
+ build-and-test:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - machine: windows-2022
+ dotnet-version: "9.0.303"
+ - machine: ubuntu-22.04
+ dotnet-version: "9.0.303"
+ - machine: macos-13
+ dotnet-version: "9.0.303"
+ - machine: ubuntu-22.04-arm
+ dotnet-version: "9.0.303"
+ runs-on: ${{ matrix.machine }}
+ defaults:
+ run:
+ working-directory: next-gen
+ steps:
+
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag: v4.2.2
+ with:
+ fetch-depth: 0 # fetching all, needed to correctly calculate version
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # tag: v4.3.1
+ with:
+ dotnet-version: ${{ matrix.dotnet-version }}
+ global-json-file: next-gen/global.json
+
+ - name: Check for NuGet packages cache
+ uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # tag: v4.2.3
+ id: nuget-cache
+ with:
+ key: next-gen-${{ hashFiles('next-gen/**/Directory.packages.props', 'next-gen/**/*.csproj') }}
+ path: ${{ env.NUGET_PACKAGES }}
+
+ - name: Restore NuGet packages
+ run: dotnet restore next-gen.sln
+
+ - name: Build solution
+ run: dotnet build next-gen.sln --configuration Release --no-restore
+
+ - name: Run tests
+ run: dotnet test next-gen.sln --configuration Release --no-build --verbosity normal --logger trx --results-directory test-results
+
+ - name: Upload test results
+ if: always()
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2
+ with:
+ name: test-results-${{ matrix.machine }}
+ path: next-gen/test-results/
+
+ code-quality:
+ runs-on: ubuntu-22.04
+ defaults:
+ run:
+ working-directory: next-gen
+ steps:
+
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag: v4.2.2
+ with:
+ fetch-depth: 0 # fetching all, needed to correctly calculate version
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # tag: v4.3.1
+ with:
+ dotnet-version: "9.0.303"
+ global-json-file: next-gen/global.json
+
+ - name: Check for NuGet packages cache
+ uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # tag: v4.2.3
+ id: nuget-cache
+ with:
+ key: next-gen-${{ hashFiles('next-gen/**/Directory.packages.props', 'next-gen/**/*.csproj') }}
+ path: ${{ env.NUGET_PACKAGES }}
+
+ - name: Restore NuGet packages
+ run: dotnet restore next-gen.sln
+
+ - name: Check formatting
+ run: dotnet format next-gen.sln --verify-no-changes --verbosity diagnostic
+
+ - name: Build solution with warnings as errors
+ run: dotnet build next-gen.sln --configuration Release --no-restore /warnaserror
+
+ security-scan:
+ runs-on: ubuntu-22.04
+ defaults:
+ run:
+ working-directory: next-gen
+ steps:
+
+ - name: Checkout
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag: v4.2.2
+ with:
+ fetch-depth: 0 # fetching all, needed to correctly calculate version
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@67a3573c9a986a3f9c594539f4ab511d57bb3ce9 # tag: v4.3.1
+ with:
+ dotnet-version: "9.0.303"
+ global-json-file: next-gen/global.json
+
+ - name: Restore NuGet packages
+ run: dotnet restore next-gen.sln
+
+ - name: Run security scan
+ run: |
+ # Run the vulnerability scan and capture output
+ dotnet list next-gen.sln package --vulnerable --include-transitive --format json > vulnerability-report.json || true
+
+ echo "Generated vulnerability report:"
+ cat vulnerability-report.json
+
+ # Check if there are actual vulnerabilities by looking for the vulnerabilities array with content
+ # The JSON structure includes "vulnerabilities": [...] only when actual vulnerabilities exist
+ if grep -q '"vulnerabilities":\s*\[[^]]\+\]' vulnerability-report.json; then
+ echo "Security vulnerabilities detected!"
+ exit 1
+ else
+ echo "No security vulnerabilities found."
+ fi
+
+ - name: Upload vulnerability report
+ if: always()
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2
+ with:
+ name: vulnerability-report
+ path: next-gen/vulnerability-report.json
+
+ summary:
+ runs-on: ubuntu-22.04
+ needs:
+ - build-and-test
+ - code-quality
+ - security-scan
+ if: always()
+ steps:
+
+ - name: Check if all jobs passed
+ run: |
+ echo "Build and test result: ${{ needs.build-and-test.result }}"
+ echo "Code quality result: ${{ needs.code-quality.result }}"
+ echo "Security scan result: ${{ needs.security-scan.result }}"
+
+ if [ "${{ needs.build-and-test.result }}" != "success" ]; then
+ echo "Build and test failed"
+ exit 1
+ fi
+
+ if [ "${{ needs.code-quality.result }}" != "success" ]; then
+ echo "Code quality checks failed"
+ exit 1
+ fi
+
+ if [ "${{ needs.security-scan.result }}" != "success" ]; then
+ echo "Security scan failed"
+ exit 1
+ fi
+
+ echo "All checks passed successfully!"
diff --git a/next-gen/Directory.Build.props b/next-gen/Directory.Build.props
index 757f3ce60d..af270b422a 100644
--- a/next-gen/Directory.Build.props
+++ b/next-gen/Directory.Build.props
@@ -5,7 +5,7 @@
$(MSBuildProjectName.Contains('.Test'))
true
- $(RepoRoot)\KeyPair.snk
+ $(MSBuildThisFileDirectory)keypair.snk
OpenTelemetry Authors
Copyright © $([System.DateTime]::Now.ToString(yyyy))
diff --git a/next-gen/NEXT-GEN-CI-TESTING.md b/next-gen/NEXT-GEN-CI-TESTING.md
new file mode 100644
index 0000000000..efbed7db6a
--- /dev/null
+++ b/next-gen/NEXT-GEN-CI-TESTING.md
@@ -0,0 +1,132 @@
+# Next-Gen CI Testing Guide
+
+This document explains how to test the new `next-gen-ci` workflow locally before pushing changes.
+
+## Overview
+
+The `next-gen-ci` workflow is designed specifically for the `out-of-process-collection` branch and only runs when changes are made to files within the `next-gen/` folder.
+
+## Features
+
+- **Smart triggering**: Only runs on `out-of-process-collection` branch when `next-gen/**` files change
+- **Multi-platform testing**: Windows, Linux, macOS, and ARM64
+- **Comprehensive checks**: Build, test, code quality, and security scanning
+- **Proper isolation**: All operations scoped to `next-gen` folder
+- **No conflicts**: Won't interfere with main branch CI when syncing changes
+- **Standard SDK versions**: Uses repository-standard .NET 9.0.303
+
+## Local Testing with `act`
+
+### Prerequisites
+
+1. **Install act**:
+ ```powershell
+ winget install nektos.act
+ ```
+
+2. **Docker**: Required for running containers
+ ```powershell
+ docker --version
+ ```
+
+### Quick Validation Scripts
+
+Two PowerShell scripts are provided for testing:
+
+#### 1. Basic Build Validation
+```powershell
+.\validate-next-gen.ps1
+```
+This script tests the actual .NET build process in the `next-gen` folder:
+- Package restore
+- Solution build
+- Test execution
+- Code formatting checks
+
+#### 2. Workflow Testing
+```powershell
+.\test-next-gen-ci.ps1
+```
+This script validates the GitHub Actions workflow:
+- Workflow syntax validation
+- Dry-run of all jobs
+- Confirms workflow structure
+
+### Manual Testing with `act`
+
+#### Test All Jobs (Dry Run)
+```bash
+# Test workflow syntax
+act -W .github/workflows/next-gen-ci.yml --list
+
+# Test individual jobs (dry run)
+act -W .github/workflows/next-gen-ci.yml -j build-and-test -n
+act -W .github/workflows/next-gen-ci.yml -j code-quality -n
+act -W .github/workflows/next-gen-ci.yml -j security-scan -n
+act -W .github/workflows/next-gen-ci.yml -j summary -n
+```
+
+#### Run Jobs for Real
+```bash
+# Run security scan (fastest)
+act -W .github/workflows/next-gen-ci.yml -j security-scan
+
+# Run code quality checks
+act -W .github/workflows/next-gen-ci.yml -j code-quality
+
+# Run full build and test (slowest, but most comprehensive)
+act -W .github/workflows/next-gen-ci.yml -j build-and-test -P ubuntu-22.04=catthehacker/ubuntu:act-22.04
+```
+
+### Expected Results
+
+#### ✅ Successful Validation
+- All projects build without errors
+- Tests pass (may have some warnings)
+- Code formatting issues are reported as warnings (can be fixed)
+- Security scan completes without vulnerabilities
+
+#### ❌ Common Issues
+- **Build failures**: Check if dependencies are restored
+- **Test failures**: Review test output in generated artifacts
+- **Format issues**: Run `dotnet format next-gen.sln` to fix
+- **Security issues**: Review and update vulnerable packages
+
+## Workflow Jobs
+
+### 1. `build-and-test`
+- **Purpose**: Build solution and run tests on multiple platforms
+- **Platforms**: Windows 2022, Ubuntu 22.04, macOS 13, Ubuntu ARM64
+- **Artifacts**: Test results for each platform
+
+### 2. `code-quality`
+- **Purpose**: Check code formatting and build with warnings as errors
+- **Platform**: Ubuntu 22.04
+- **Checks**: `dotnet format` and warning-free build
+
+### 3. `security-scan`
+- **Purpose**: Scan for vulnerable NuGet packages
+- **Platform**: Ubuntu 22.04
+- **Artifacts**: Vulnerability report (if any found)
+
+### 4. `summary`
+- **Purpose**: Aggregate results from all other jobs
+- **Dependency**: Runs after all other jobs complete
+- **Behavior**: Fails if any dependent job fails
+
+## Tips for Development
+
+1. **Test locally first**: Use the validation scripts before pushing
+2. **Fix formatting**: Run `dotnet format next-gen.sln` to resolve style issues
+3. **Check security**: Review any reported vulnerabilities
+4. **Platform-specific issues**: Use `act` to test on Linux containers if developing on Windows
+
+## Integration with Main Branch
+
+This workflow is designed to:
+- **Not conflict** with the main branch CI when syncing changes
+- **Only run** when `next-gen/` files are modified
+- **Use separate** artifact names to avoid collisions
+- **Provide** clear status checks for the `out-of-process-collection` branch
+
+The main CI workflow remains unchanged, preventing merge conflicts during branch synchronization.
diff --git a/next-gen/src/OpenTelemetry.AutoInstrumentation.Sdk/BatchExportProcessorAsync.cs b/next-gen/src/OpenTelemetry.AutoInstrumentation.Sdk/BatchExportProcessorAsync.cs
index 527955e8ed..107fdf3e27 100644
--- a/next-gen/src/OpenTelemetry.AutoInstrumentation.Sdk/BatchExportProcessorAsync.cs
+++ b/next-gen/src/OpenTelemetry.AutoInstrumentation.Sdk/BatchExportProcessorAsync.cs
@@ -35,8 +35,8 @@ protected BatchExportProcessorAsync(
IExporterAsync exporter,
BatchExportProcessorOptions options)
{
+ // Validate all parameters first, before initializing anything
ArgumentNullException.ThrowIfNull(options);
-
_Logger = logger ?? throw new ArgumentNullException(nameof(logger));
_Exporter = exporter ?? throw new ArgumentNullException(nameof(exporter));
@@ -46,6 +46,7 @@ protected BatchExportProcessorAsync(
_ExportIntervalMilliseconds = options.ExportIntervalMilliseconds;
_ExportTimeoutMilliseconds = options.ExportTimeoutMilliseconds;
+ // Only start the thread after all validation and initialization is complete
_ExporterThread = new Thread(ExporterProc)
{
IsBackground = true,
@@ -196,7 +197,14 @@ private void ExporterProc(object? state)
ExportAsync().ContinueWith(
static (t, o) =>
{
- ((EventWaitHandle)o!).Set();
+ try
+ {
+ ((EventWaitHandle)o!).Set();
+ }
+ catch (ObjectDisposedException)
+ {
+ // EventWaitHandle was disposed during shutdown, nothing to signal
+ }
},
_ExportAsyncTaskCompleteTrigger,
CancellationToken.None,
@@ -205,6 +213,11 @@ private void ExporterProc(object? state)
_ExportAsyncTaskCompleteTrigger.WaitOne();
}
+ catch (ObjectDisposedException)
+ {
+ // The processor is being disposed, exit the worker thread
+ return;
+ }
finally
{
_BufferedBatch.Reset();
diff --git a/next-gen/test-next-gen-ci.ps1 b/next-gen/test-next-gen-ci.ps1
new file mode 100644
index 0000000000..86643ae429
--- /dev/null
+++ b/next-gen/test-next-gen-ci.ps1
@@ -0,0 +1,65 @@
+#!/usr/bin/env pwsh
+# Test script for next-gen CI workflow
+
+Write-Host "Testing next-gen-ci workflow locally..." -ForegroundColor Green
+
+# Check if we're in the right directory
+if (-not (Test-Path "next-gen")) {
+ Write-Host "❌ Error: next-gen folder not found. Are you in the repo root?" -ForegroundColor Red
+ exit 1
+}
+
+# Check if required files exist
+$requiredFiles = @(
+ "next-gen/global.json",
+ "next-gen/next-gen.sln",
+ ".github/workflows/next-gen-ci.yml"
+)
+
+foreach ($file in $requiredFiles) {
+ if (-not (Test-Path $file)) {
+ Write-Host "❌ Error: Required file not found: $file" -ForegroundColor Red
+ exit 1
+ } else {
+ Write-Host "✅ Found: $file" -ForegroundColor Green
+ }
+}
+
+# Test the workflow syntax
+Write-Host "`n🔍 Testing workflow syntax..." -ForegroundColor Yellow
+try {
+ $result = act -W .github/workflows/next-gen-ci.yml --list 2>&1
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "✅ Workflow syntax is valid" -ForegroundColor Green
+ } else {
+ Write-Host "❌ Workflow syntax error:" -ForegroundColor Red
+ Write-Host $result
+ exit 1
+ }
+} catch {
+ Write-Host "❌ Error running act: $($_.Exception.Message)" -ForegroundColor Red
+ exit 1
+}
+
+# Test dry run of each job
+$jobs = @("build-and-test", "code-quality", "security-scan", "summary")
+
+foreach ($job in $jobs) {
+ Write-Host "`n🧪 Testing job: $job" -ForegroundColor Yellow
+ try {
+ $result = act -W .github/workflows/next-gen-ci.yml -j $job -n 2>&1
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "✅ Job $job dry-run successful" -ForegroundColor Green
+ } else {
+ Write-Host "❌ Job $job dry-run failed:" -ForegroundColor Red
+ Write-Host $result
+ }
+ } catch {
+ Write-Host "❌ Error testing job $job`: $($_.Exception.Message)" -ForegroundColor Red
+ }
+}
+
+Write-Host "`n🎉 Testing completed!" -ForegroundColor Green
+Write-Host "To run a specific job for real, use:" -ForegroundColor Cyan
+Write-Host " act -W .github/workflows/next-gen-ci.yml -j " -ForegroundColor Cyan
+Write-Host "`nAvailable jobs: build-and-test, code-quality, security-scan, summary" -ForegroundColor Cyan
diff --git a/next-gen/test/OpenTelemetry.AutoInstrumentation.Sdk.Tests/OpenTelemetry.AutoInstrumentation.Sdk.Tests.csproj b/next-gen/test/OpenTelemetry.AutoInstrumentation.Sdk.Tests/OpenTelemetry.AutoInstrumentation.Sdk.Tests.csproj
index 094c399717..b8a1e22b17 100644
--- a/next-gen/test/OpenTelemetry.AutoInstrumentation.Sdk.Tests/OpenTelemetry.AutoInstrumentation.Sdk.Tests.csproj
+++ b/next-gen/test/OpenTelemetry.AutoInstrumentation.Sdk.Tests/OpenTelemetry.AutoInstrumentation.Sdk.Tests.csproj
@@ -2,6 +2,8 @@
$(TestTargetFrameworks)
+
+ $(NoWarn);CA1515;CA2007
diff --git a/next-gen/validate-next-gen.ps1 b/next-gen/validate-next-gen.ps1
new file mode 100644
index 0000000000..57ff894775
--- /dev/null
+++ b/next-gen/validate-next-gen.ps1
@@ -0,0 +1,69 @@
+#!/usr/bin/env pwsh
+# Simple validation of next-gen folder build process
+
+Write-Host "🔍 Validating next-gen build process..." -ForegroundColor Green
+
+# Change to next-gen directory
+Set-Location "next-gen"
+
+# Check if we can restore packages
+Write-Host "`n📦 Testing package restore..." -ForegroundColor Yellow
+try {
+ $result = dotnet restore next-gen.sln
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "✅ Package restore successful" -ForegroundColor Green
+ } else {
+ Write-Host "❌ Package restore failed" -ForegroundColor Red
+ exit 1
+ }
+} catch {
+ Write-Host "❌ Error during package restore: $($_.Exception.Message)" -ForegroundColor Red
+ exit 1
+}
+
+# Check if we can build
+Write-Host "`n🔨 Testing build..." -ForegroundColor Yellow
+try {
+ $result = dotnet build next-gen.sln --configuration Release --no-restore
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "✅ Build successful" -ForegroundColor Green
+ } else {
+ Write-Host "❌ Build failed" -ForegroundColor Red
+ exit 1
+ }
+} catch {
+ Write-Host "❌ Error during build: $($_.Exception.Message)" -ForegroundColor Red
+ exit 1
+}
+
+# Check if we can run tests
+Write-Host "`n🧪 Testing test execution..." -ForegroundColor Yellow
+try {
+ $result = dotnet test next-gen.sln --configuration Release --no-build --verbosity normal
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "✅ Tests successful" -ForegroundColor Green
+ } else {
+ Write-Host "⚠️ Tests completed with issues (this might be expected)" -ForegroundColor Yellow
+ }
+} catch {
+ Write-Host "❌ Error during test execution: $($_.Exception.Message)" -ForegroundColor Red
+}
+
+# Check formatting
+Write-Host "`n📝 Testing code formatting..." -ForegroundColor Yellow
+try {
+ $result = dotnet format next-gen.sln --verify-no-changes --verbosity minimal
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host "✅ Code formatting is correct" -ForegroundColor Green
+ } else {
+ Write-Host "⚠️ Code formatting issues detected" -ForegroundColor Yellow
+ }
+} catch {
+ Write-Host "❌ Error during formatting check: $($_.Exception.Message)" -ForegroundColor Red
+}
+
+Write-Host "`n🎉 Validation completed!" -ForegroundColor Green
+Write-Host "The next-gen CI workflow should work correctly with this setup." -ForegroundColor Cyan
+
+# Return to original directory
+Set-Location ".."