|
| 1 | +# Multi-instance local runner (NGINX proxy) |
| 2 | + |
| 3 | +Use `start-local-fhir-nginx.ps1` to spin up multiple local FHIR R4 instances behind an NGINX reverse proxy on a single port. Default settings start three instances on ports 5001-5003 and expose them via http://localhost:4343. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | +- PowerShell 7+ |
| 7 | +- .NET SDK matching `global.json` |
| 8 | +- `sqlcmd` available on PATH (for optional DB creation) |
| 9 | +- Local SQL Server instance reachable by the provided connection string |
| 10 | + |
| 11 | +## Quick start |
| 12 | +```pwsh |
| 13 | +pwsh ./Tools/MultiInstanceRunner/start-local-fhir-nginx.ps1 -PersistTestEnvironment |
| 14 | +``` |
| 15 | +This builds the R4 project (unless `-SkipBuild`), ensures the DB exists (unless `-SkipSchemaInitialization`), starts NGINX, and launches the configured number of instances. |
| 16 | + |
| 17 | +## Key parameters |
| 18 | +- `-InstanceCount` (default 3): number of FHIR processes; they bind sequentially starting at `-BasePort`. |
| 19 | +- `-BasePort` (default 5001): first backend port; instances use BasePort..BasePort+InstanceCount-1. |
| 20 | +- `-NginxListenPort` (default 4343): public listener forwarding to backends. |
| 21 | +- `-SqlConnectionString` / `-DatabaseName`: SQL connection; normalized to strip wrappers and ensure DB name. |
| 22 | +- `-ProjectPath` (default `src/Microsoft.Health.Fhir.R4.Web`): project to run. |
| 23 | +- `-Framework` (default `net9.0`): target framework for build/run. |
| 24 | +- `-SkipBuild`: reuse existing build outputs. |
| 25 | +- `-SkipSchemaInitialization`: skip schema manager apply. |
| 26 | +- `-DisableSecurity`: disable auth locally (default: on). |
| 27 | +- `-RedirectOutput`: write per-instance logs to `.local/logs`. |
| 28 | +- `-PersistTestEnvironment`: also write TestEnvironment* vars to the user profile. |
| 29 | + |
| 30 | +## Environment variables set per instance |
| 31 | +- `ASPNETCORE_URLS`, `ASPNETCORE_ENVIRONMENT` |
| 32 | +- `DataStore=SqlServer`, `SqlServer:ConnectionString`, `SqlServer:AllowDatabaseCreation=true`, `SqlServer:DeleteAllDataOnStartup=false` |
| 33 | +- `TaskHosting:*` tuned for fast background jobs |
| 34 | +- `FhirServer:CoreFeatures:SearchParameterCacheRefreshIntervalSeconds=1`, `SearchParameterCacheRefreshMaxInitialDelaySeconds=0` |
| 35 | +- Reindex/Export/ConvertData/Import enabled |
| 36 | +- Logging levels set to Debug for Microsoft.Health/Microsoft/System |
| 37 | + |
| 38 | +## Stopping |
| 39 | +- Press Ctrl+C in the PowerShell session to stop dotnet processes. |
| 40 | +- To stop NGINX manually: |
| 41 | + ```pwsh |
| 42 | + nginx -p $repoRoot/.local/nginx -s stop |
| 43 | + ``` |
| 44 | + |
| 45 | +## Logs |
| 46 | +When `-RedirectOutput` is set, stdout/stderr go to `.local/logs/fhir-r4-<port>.out.log` and `.err.log`. NGINX logs live under `.local/nginx/logs`. |
| 47 | + |
| 48 | +## Running E2E tests against the cluster |
| 49 | +1) Start the multi-instance cluster (example): |
| 50 | +```pwsh |
| 51 | +pwsh ./Tools/MultiInstanceRunner/start-local-fhir-nginx.ps1 -NoLaunchProfile -RedirectOutput -PersistTestEnvironment |
| 52 | +``` |
| 53 | +2) In another shell from repo root, run the desired E2E suite pointing at the proxy (env vars are already set by the script): |
| 54 | +```pwsh |
| 55 | +dotnet test .\test\Microsoft.Health.Fhir.R4.Tests.E2E\Microsoft.Health.Fhir.R4.Tests.E2E.csproj -f net9.0 --no-build --filter "FullyQualifiedName~Microsoft.Health.Fhir.Tests.E2E.Rest.Reindex.ReindexTests&DisplayName~SqlServer" /p:CollectCoverage=false |
| 56 | +``` |
| 57 | +Notes: |
| 58 | +- The script sets `TestEnvironmentUrl*` to http://localhost:4343 (via `-PersistTestEnvironment`). |
| 59 | +- Ensure the runner keeps running while tests execute; stop it after tests finish. |
| 60 | + |
| 61 | +## Sample endpoints (default proxy port 4343) |
| 62 | +- Health: http://localhost:4343/health/check |
| 63 | +- Metadata (capability statement): http://localhost:4343/metadata |
| 64 | +- Patient search: http://localhost:4343/Patient |
| 65 | + |
| 66 | +## Debugging with Visual Studio |
| 67 | +### Attach debugger to a running instance |
| 68 | +1) Open the solution in Visual Studio (e.g., `Microsoft.Health.Fhir.sln`) |
| 69 | +2) Go to **Debug → Attach to Process...** (or press **Ctrl+Alt+P**) |
| 70 | +  |
| 71 | +3) In the "Attach to Process" dialog: |
| 72 | + - Confirm **Connection type** is set to "Local" |
| 73 | + - In the process list, look for **Microsoft.Health.Fhir.R4.Web.exe** entries |
| 74 | + - Each running instance will appear in the list with its PID |
| 75 | + - Select the instance(s) you want to debug and click **Attach** |
| 76 | +  |
| 77 | +4) Set breakpoints in your code (e.g., in SearchParameterOperations.cs or SqlStoreClient.cs) |
| 78 | +5) Make requests via the proxy (http://localhost:4343) to hit the breakpoints |
| 79 | + |
| 80 | +### Debugging multiple instances |
| 81 | +- You can attach to multiple `Microsoft.Health.Fhir.R4.Web.exe` processes simultaneously |
| 82 | +- When a request comes through the NGINX proxy, it routes to one of the backends; use breakpoints to identify which instance handled it |
| 83 | +- Check the Visual Studio **Debug → Processes** window to see all attached processes |
| 84 | + |
| 85 | +### Tips |
| 86 | +- If you attached to instance on port 5001 and want to debug port 5002, use **Debug → Reattach to Microsoft.Health.Fhir.R4.Web.exe** (keyboard: **Shift+Alt+P**) as a shortcut |
| 87 | +- Ensure the solution is built before attaching so symbols are available |
| 88 | +- Use conditional breakpoints (right-click breakpoint → Filter) to target specific requests |
0 commit comments