Skip to main content

Manager

The Manager is the core service of AI Smart Redact. It exposes the Manager API, persists job state in a database, encrypts files at rest, and dispatches detection and redaction work to the Worker. Set environment variables on the Manager container to configure it; the default port is 9982. For the naming convention and shared notes, refer to Configuration reference.

Default appsettings.json

{
"Database": {
"DatabaseType": "SqlLite"
},
"FileStorage": {
"FileStorageType": "HostFileSystem",
"FilesDirectoryPath": "/app/storage_folder"
},
"Encryption": {
"EncryptionKey": "<ENCRYPTION_KEY>",
"DekTokenTtlMinutes": 1440
},
"ServiceCommunication": {
"ServiceCommunicationType": "Rest",
"ConnectionString": "http://localhost:4885/"
},
"JobOptions": {
"TimeoutMinutes": 60
},
"Licensing": {
"LicenseKey": "<LICENSE_KEY>",
"LgsURL": ""
},
"WebServer": {
"PortNumber": 9982,
"MaxFileSizeBytes": 104857600,
"MaxConcurrentConnections": 1000,
"RequestHeadersTimeout": null,
"KeepAliveTimeout": null,
"MinRequestBodyDataRateBytesPerSecond": null,
"MinRequestBodyDataRateGracePeriod": null
},
"LogFilePath": "./logs/smart-redact-manager-log.txt",
"LogRetentionDays": 7
}

Each section is described below.

Licensing

AI Smart Redact requires a valid license key. The Manager performs soft validation: it starts even with a missing or invalid key, but rejects API requests with 403 Forbidden until a valid key is configured.

Licensing__LicenseKey=<LICENSE_KEY>
SettingDefaultDescription
LicenseKeyrequiredThe AI Smart Redact license key issued by Pdftools.
LgsURLOptional URL of an on-premise License Gateway Service for air-gapped deployments.

Database

The Manager stores job and file metadata in a relational database. The Database section selects the engine and provides a connection string.

Database__DatabaseType=PostgreSql
Database__ConnectionString=Host=...;Database=...;Username=...;Password=...
SettingDefaultDescription
DatabaseTyperequiredOne of PostgreSql, SqlLite.
ConnectionStringrequired (except SqlLite)Provider-specific connection string.

File storage

PDFs uploaded through the Manager API and the FDF and redacted-PDF outputs produced by jobs are persisted to a file store. The Worker reads from and writes to the same store, so the Manager and Worker must share the FileStorage configuration.

FileStorage__FileStorageType=AwsS3
FileStorage__ConnectionString=<BUCKET_NAME>;<REGION>
SettingDefaultDescription
FileStorageTyperequiredOne of HostFileSystem, AwsS3, MinIO.
ConnectionStringrequired for AwsS3, MinIOBackend-specific connection string. Format depends on FileStorageType.
FilesDirectoryPathrequired for HostFileSystemFilesystem path used when FileStorageType is HostFileSystem.

Connection string formats

  • AwsS3: <BUCKET_NAME>;<REGION> (or the full form aws.s3://bucket=<BUCKET_NAME>;region=<REGION>).
  • MinIO: minio.s3://keyId=<MINIO_ACCESS_KEY>;key=<MINIO_SECRET_KEY>;bucket=<BUCKET_NAME>;serviceUrl=<MINIO_URL> (or aws.s3://keyId=<MINIO_ACCESS_KEY>;key=<MINIO_SECRET_KEY>;bucket=<BUCKET_NAME>;serviceUrl=<MINIO_URL>). The MinIO secret key parameter is named key=, matching the underlying S3 client.
  • HostFileSystem: not used; configure FilesDirectoryPath instead.

Encryption

Files at rest are encrypted with AES-256-GCM. The Manager wraps each file’s data encryption key (DEK) in a short-lived, AES-GCM-encrypted token, the DEK token, returned to the client at upload time; subsequent operations on the file require the token. The Worker uses the same Encryption configuration as the Manager: both services must agree on the key.

Encryption__EncryptionKey=<ENCRYPTION_KEY>
Encryption__DekTokenTtlMinutes=1440
SettingDefaultDescription
EncryptionKeyrequiredBase64-encoded 32-byte key encryption key (KEK). Generate with openssl rand -base64 32.
DekTokenTtlMinutes1440DEK token lifetime in minutes (default: 24 hours). Files and jobs are retained for at least ceil(DekTokenTtlMinutes / 1440) days; sub-day TTLs still round up to one day. A daily cleanup then deletes expired entries, so files can outlive the TTL by up to another 24 hours.

Service communication

The Manager dispatches detection and redaction jobs to the Worker. The transport, broker location, concurrency limits, and resilience policies live under ServiceCommunication.

Transport

Selects how the Manager sends jobs to the Worker. With Rest, the Manager calls the Worker directly over HTTP, suitable for single-Worker deployments. With RabbitMQ, the Manager publishes jobs to a queue and Workers consume them; this lets multiple Worker instances share the load.

ServiceCommunication__ServiceCommunicationType=RabbitMQ
ServiceCommunication__Host=<RABBITMQ_HOST>
ServiceCommunication__Username=<USERNAME>
ServiceCommunication__Password=<PASSWORD>

For REST transport, the connection string points to the Worker URL:

ServiceCommunication__ServiceCommunicationType=Rest
ServiceCommunication__ConnectionString=http://<WORKER_HOST>:4885/
SettingDefaultDescription
ServiceCommunicationTyperequiredRest or RabbitMQ. The Worker must use the same value.
ConnectionStringrequired for RestBase URL of the Worker.
Hostrequired for RabbitMQRabbitMQ host name.
Usernamerequired for RabbitMQRabbitMQ username.
Passwordrequired for RabbitMQRabbitMQ password.
RetryCount3Retries on transport-level failures (Manager → Worker) before the message is moved to the error queue. Distinct from the Orchestrator’s MaxDetectionRetries, which retries at the Orchestrator → Manager layer.

REST concurrency

Caps on how many concurrent REST calls the Manager sends to the Worker. Applies only when ServiceCommunicationType is Rest; with RabbitMQ, the broker handles dispatch and the per-Worker concurrency is configured on the Worker. The Worker-side limits live on the Worker configuration page.

ServiceCommunication__RestSemaphoreLimit=10
SettingDefaultDescription
RestSemaphoreLimit10Maximum concurrent REST calls from the Manager to the Worker.
RestSemaphoreTimeoutSecondsnull (infinite)Time a request waits for a free semaphore slot before being rejected with 429.

Admission control

A safeguard against unbounded queue buildup. When the in-progress job count reaches the configured limit, the Manager rejects new requests with 429 Too Many Requests instead of letting work pile up. Without it, a sustained burst of requests can grow the queue indefinitely and degrade end-to-end latency without any visible signal to clients.

Admission control is disabled by default. Set MaxPendingJobs to enable it. Optionally set HealthCheckPendingJobThreshold so the readiness probe reports Degraded before the hard limit is reached. The values below are an illustrative starting point:

ServiceCommunication__MaxPendingJobs=20
ServiceCommunication__HealthCheckPendingJobThreshold=15
SettingDefaultDescription
MaxPendingJobsnull (disabled)Maximum in-progress jobs across all types. New requests are rejected with 429 once the limit is reached.
HealthCheckPendingJobThresholdnull (disabled)Pending-job count at or above which /healthz/ready reports Degraded.
BackpressureMonitorIntervalSeconds5How often the cached pending-job count is refreshed from the database.

Circuit breaker

Detects repeated transport failures and fast-fails new requests instead of waiting for each one to time out. After the configured number of consecutive failures, the Manager rejects new requests for a cool-down period before probing again. This prevents cascading slowdowns when the Worker is unavailable. Enabled by default.

ServiceCommunication__CircuitBreakerFailureThreshold=3
ServiceCommunication__CircuitBreakerDurationSeconds=30
SettingDefaultDescription
CircuitBreakerFailureThreshold3Consecutive transport failures before the circuit opens. Set to null to disable.
CircuitBreakerDurationSeconds30Seconds the circuit stays open before allowing a probe request.

Job options

JobOptions__TimeoutMinutes=60
SettingDefaultDescription
TimeoutMinutes60Maximum total lifetime of a job, including queue time and Worker processing. Range 1 to 1440 minutes (24 hours). Jobs that exceed the deadline are marked as failed.

Web server

The WebServer section configures the Kestrel HTTP server.

WebServer__PortNumber=9982
WebServer__MaxFileSizeBytes=104857600
WebServer__MaxConcurrentConnections=1000
SettingDefaultDescription
PortNumber9982TCP port the Manager listens on.
MaxFileSizeBytes104857600 (100 MB)Maximum allowed multipart upload size. Oversized uploads return 413. Set to null, 0, or a negative value to remove the limit.
MaxConcurrentConnections1000Maximum concurrent connections accepted by Kestrel. Excess connections are rejected at the TCP level. Set to null, 0, or a negative value to remove the limit.
RequestHeadersTimeoutnull (Kestrel default)Maximum time spent waiting for request headers. Format: hh:mm:ss.
KeepAliveTimeoutnull (Kestrel default)Idle-connection lifetime. Format: hh:mm:ss.
MinRequestBodyDataRateBytesPerSecondnull (Kestrel default)Minimum upload rate before Kestrel disconnects a slow client. Set to 0 to disable the check.
MinRequestBodyDataRateGracePeriodnull (Kestrel default)Grace period before the minimum upload rate is enforced. Format: hh:mm:ss.

If both the Manager and the Orchestrator are deployed, configure the same MaxFileSizeBytes value on both. Otherwise the Orchestrator can accept files that the Manager later rejects.

Logging

Application logs are written to the console and, optionally, to a file. The fields are top-level (no section prefix).

LogFilePath=./logs/smart-redact-manager-log.txt
LogRetentionDays=7
SettingDefaultDescription
LogFilePathPath of the rolling-daily log file inside the container. Leave empty to disable file logging.
LogRetentionDays7Number of days log files are retained on disk.

The minimum log level isn’t a separate setting. It’s derived from the standard ASPNETCORE_ENVIRONMENT environment variable: when set to Development, the service emits Debug-level logs in a developer-friendly console format; any other value (the default) emits Information-level logs in JSON. Use Development only for local diagnostics.