SMS Router Configuration¶
This reference covers properties consumed by sms-router-service. Installation commands and shared infrastructure are documented in bare-metal installation and Docker deployments.
Runtime and service discovery¶
| Property | Default | Environment | Description |
|---|---|---|---|
server.port |
0 base; 9015 dev |
SERVER_PORT |
HTTP port used by the service. The main configuration lets the system choose a port, while the development profile uses port 9015. Docker health checks also use 9015. |
server.shutdown |
graceful |
SERVER_SHUTDOWN |
Controls how the service stops. graceful waits for current HTTP requests to finish when the process receives SIGTERM. |
spring.profiles.active |
dev |
ACTIVE_PROFILE or SPRING_PROFILES_ACTIVE |
Selects the active Spring profile. The default is dev. |
spring.application.name |
sms-router-service |
SPRING_APPLICATION_NAME |
Service name used by Spring, Eureka, and load balancing. |
spring.lifecycle.timeout-per-shutdown-phase |
30s |
SPRING_LIFECYCLE_TIMEOUT_PER_SHUTDOWN_PHASE |
Maximum time allowed for each clean shutdown phase. |
spring.task.scheduling.pool.size |
4 |
SCHEDULING_POOL_SIZE |
Number of threads shared by campaign, outbox, recovery, and cleanup jobs. |
eureka.client.service-url.defaultZone |
http://localhost:8761/eureka/ |
EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE |
URL of the Eureka server used for service registration and discovery. |
eureka.instance.prefer-ip-address |
true |
EUREKA_INSTANCE_PREFER_IP_ADDRESS |
Controls whether Eureka registers the service by IP address or hostname. true uses the IP address; false uses the hostname. |
The router finds client-service through Eureka. It waits up to 5 seconds to connect and 10 seconds for a response. These timeouts are set in code and cannot be changed through configuration.
Security and actuator¶
| Property | Default | Environment | Description |
|---|---|---|---|
admin.api.key |
empty | ADMIN_API_KEY |
Shared key required for /admin/**, /internal/**, protected actuator endpoints, and router requests to client-service. If the value is empty, all these requests fail authentication. |
server.servlet.context-path |
empty | SERVER_SERVLET_CONTEXT_PATH |
Optional path added before every service endpoint. The actuator security filter also uses this path. |
management.endpoints.web.base-path |
/actuator |
MANAGEMENT_ENDPOINTS_WEB_BASE_PATH |
Main URL path for actuator endpoints and health checks. |
management.endpoints.web.exposure.include |
health,info,metrics,scheduledtasks,loggers,threaddump,env,configprops,flyway |
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE |
Lists the actuator endpoints available over HTTP. heapdump is not included. |
management.endpoint.health.probes.enabled |
true |
MANAGEMENT_ENDPOINT_HEALTH_PROBES_ENABLED |
Turns liveness and readiness health checks on or off. true enables both health groups. |
management.endpoint.health.show-details |
always |
MANAGEMENT_ENDPOINT_HEALTH_SHOW_DETAILS |
Controls when full health details are shown. The default always shows them, so the admin key must protect the combined health endpoint. |
The public paths are /actuator/health/liveness, /actuator/health/readiness, and /actuator/info. The combined /actuator/health endpoint and all other actuator endpoints require the admin key. Do not disable Spring Security for actuator paths. The firewall and security filters protect these endpoints.
Database, Flyway, and connection pool¶
| Property | Default | Environment | Description |
|---|---|---|---|
spring.datasource.url |
jdbc:postgresql://localhost:5432/sms_gateway?currentSchema=sms_router |
DB_URL |
JDBC URL used to connect to the sms_router PostgreSQL schema. |
spring.datasource.username |
appuser |
DB_USERNAME |
Username used to connect to PostgreSQL. |
spring.datasource.password |
apppass |
DB_PASSWORD |
Password used to connect to PostgreSQL. Replace the development value outside local development. |
spring.datasource.hikari.maximum-pool-size |
10 |
SPRING_DATASOURCE_HIKARI_MAXIMUM_POOL_SIZE |
Maximum number of database connections in the pool. Account for both API requests and scheduled jobs when setting this value. |
spring.datasource.hikari.minimum-idle |
2 |
SPRING_DATASOURCE_HIKARI_MINIMUM_IDLE |
Minimum number of unused database connections kept ready. |
spring.datasource.hikari.connection-timeout |
30000 ms |
SPRING_DATASOURCE_HIKARI_CONNECTION_TIMEOUT |
Maximum time to wait for a database connection from the pool. |
spring.datasource.hikari.idle-timeout |
600000 ms |
SPRING_DATASOURCE_HIKARI_IDLE_TIMEOUT |
Time an unused connection can remain in the pool before it is removed. |
spring.datasource.hikari.max-lifetime |
1800000 ms |
SPRING_DATASOURCE_HIKARI_MAX_LIFETIME |
Maximum time a connection can stay in the pool. Keep it shorter than the timeout used by the database or network. |
spring.jpa.hibernate.ddl-auto |
validate |
SPRING_JPA_HIBERNATE_DDL_AUTO |
Controls how Hibernate handles the database schema. validate checks the Flyway-managed schema without changing it. Do not use update in production. |
spring.jpa.properties.hibernate.default_schema |
sms_router |
SPRING_JPA_PROPERTIES_HIBERNATE_DEFAULT_SCHEMA |
PostgreSQL schema used by JPA and Hibernate. |
spring.jpa.open-in-view |
false |
SPRING_JPA_OPEN_IN_VIEW |
Controls whether a database session stays open while an HTTP response is created. Keep this false so sessions close at transaction boundaries. |
spring.flyway.enabled |
true |
SPRING_FLYWAY_ENABLED |
Controls whether Flyway updates the database schema at startup. |
spring.flyway.baseline-on-migrate |
true |
SPRING_FLYWAY_BASELINE_ON_MIGRATE |
Allows Flyway to create a starting version for an existing schema without migration history. Review this setting carefully for a new production database. |
spring.flyway.baseline-version |
0 |
SPRING_FLYWAY_BASELINE_VERSION |
Starting migration version used when Flyway creates a baseline. |
spring.flyway.schemas / default-schema |
sms_router |
SPRING_FLYWAY_SCHEMAS, SPRING_FLYWAY_DEFAULT_SCHEMA |
Schemas that Flyway manages and uses by default. |
spring.flyway.url/user/password |
datasource-equivalent | DB_URL, DB_USERNAME, DB_PASSWORD |
Database connection values used by Flyway when it runs migrations. |
Kafka producer and outbox¶
| Property | Default | Environment | Description |
|---|---|---|---|
spring.kafka.bootstrap-servers |
localhost:9092 |
KAFKA_BOOTSTRAP_SERVERS |
Comma-separated Kafka broker addresses used for the first connection. |
spring.kafka.producer.acks |
all |
SPRING_KAFKA_PRODUCER_ACKS |
Controls how many broker confirmations are required. all waits for all current topic copies to confirm the message. |
spring.kafka.producer.retries |
5 |
SPRING_KAFKA_PRODUCER_RETRIES |
Number of times the Kafka client retries a failed send. This is separate from the application's outbox retries. |
spring.kafka.producer.properties.enable.idempotence |
true |
SPRING_KAFKA_PRODUCER_PROPERTIES_ENABLE_IDEMPOTENCE |
Prevents the Kafka producer from creating duplicate messages during supported retries. |
outbox.publisher.enabled |
true |
OUTBOX_PUBLISHER_ENABLED |
Controls whether this service publishes pending outbox rows to Kafka. false leaves new rows waiting in the outbox. |
outbox.publisher.poll-ms |
500 ms |
OUTBOX_PUBLISHER_POLL_MS |
Delay after one outbox publishing run finishes before the next run starts. |
outbox.publisher.batch-size |
50 |
OUTBOX_PUBLISHER_BATCH_SIZE |
Maximum number of outbox rows claimed in one publishing run. |
outbox.publisher.send-timeout-ms |
5000 ms |
OUTBOX_PUBLISHER_SEND_TIMEOUT_MS |
Maximum time to wait for all Kafka sends started by one batch. |
outbox.recovery.enabled |
true |
OUTBOX_RECOVERY_ENABLED |
Controls whether failed outbox rows are moved back to pending for another attempt. |
outbox.recovery.poll-ms |
60000 ms |
OUTBOX_RECOVERY_POLL_MS |
Delay between checks for failed outbox rows that can be retried. |
outbox.recovery.max-rounds |
3 |
OUTBOX_RECOVERY_MAX_ROUNDS |
Maximum number of times a failed row can be moved back to pending. |
outbox.recovery.cooldown-minutes |
5 |
OUTBOX_RECOVERY_COOLDOWN_MINUTES |
Minimum time a failed row must wait before it can be retried. |
outbox.recovery.batch-size |
100 |
OUTBOX_RECOVERY_BATCH_SIZE |
Maximum number of failed rows moved back to pending in one run. |
Disabling the publisher does not disable campaign creation or direct acceptance. Requests continue writing outbox rows, so queue depth grows until a publisher-enabled instance resumes draining them.
Multipart and bulk build¶
| Property | Default | Environment | Description |
|---|---|---|---|
spring.servlet.multipart.max-file-size |
64MB |
SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE |
Maximum size of an uploaded CSV file. |
spring.servlet.multipart.max-request-size |
64MB |
SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE |
Maximum size of the full upload request, including the file and other fields. |
campaign.bulk.max-recipients |
1000000 |
CAMPAIGN_BULK_MAX_RECIPIENTS |
Maximum number of valid recipients accepted from one CSV file. |
campaign.bulk.build.enabled |
true |
CAMPAIGN_BULK_BUILD_ENABLED |
Controls whether this service can claim and process uploaded campaign files. |
campaign.bulk.build.poll-ms |
2000 ms |
CAMPAIGN_BULK_BUILD_POLL_MS |
Delay after one campaign build check finishes before the next check starts. |
campaign.bulk.build.batch-size |
1 |
CAMPAIGN_BULK_BUILD_BATCH_SIZE |
Maximum number of uploaded files claimed in one build run. |
campaign.bulk.build.chunk-size |
1000 |
CAMPAIGN_BULK_BUILD_CHUNK_SIZE |
Number of recipients validated, priced, and saved at a time. |
campaign.bulk.build.stale-minutes |
30 |
CAMPAIGN_BULK_BUILD_STALE_MINUTES |
Time an upload can remain IN_PROGRESS before another worker can claim it. |
campaign.bulk.build.silent-claim-warn-ms |
60000 ms |
CAMPAIGN_BULK_BUILD_SILENT_CLAIM_WARN_MS |
Minimum time between warnings when queued work cannot be claimed. |
The original CSV file is stored in PostgreSQL. Plan database storage, PostgreSQL write-ahead log (WAL) space, and request memory for files up to the 64 MB HTTP limit.
Campaign schedule and regulatory window¶
| Property | Default | Environment | Description |
|---|---|---|---|
campaign.schedule.min-lead-seconds |
60 |
CAMPAIGN_SCHEDULE_MIN_LEAD_SECONDS |
Minimum number of seconds between creating a scheduled campaign and its start time. |
campaign.schedule.max-future-days |
90 |
CAMPAIGN_SCHEDULE_MAX_FUTURE_DAYS |
Maximum number of days in the future that a campaign can be scheduled. |
campaign.schedule.deadline-grace-minutes |
60 |
CAMPAIGN_SCHEDULE_DEADLINE_GRACE_MINUTES |
Extra time allowed after the scheduled start. The campaign expires at scheduledAt plus this value. |
campaign.btrc.enabled |
true |
BTRC_ENABLED or CAMPAIGN_BTRC_ENABLED |
Controls whether the BTRC promotional sending window is enforced. Disable it only in a controlled non-production environment. |
campaign.btrc.zone-id |
Asia/Dhaka |
BTRC_ZONE_ID or CAMPAIGN_BTRC_ZONE_ID |
Time zone used to check campaign schedules and sending hours. |
campaign.btrc.window.start-hour |
9 |
BTRC_WINDOW_START_HOUR |
First allowed sending hour. The hour is included in the allowed window. |
campaign.btrc.window.end-hour |
24 |
BTRC_WINDOW_END_HOUR |
Hour when sending must stop. The hour is not included; 24 means the end of the day. |
Changing the window affects new campaigns, rescheduled campaigns, and checks made when messages are sent. It does not change existing scheduled times.
Dispatcher, DLR roll-up, and retry¶
| Property | Default | Environment | Description |
|---|---|---|---|
campaign.dispatcher.enabled |
true |
CAMPAIGN_DISPATCHER_ENABLED |
Controls whether this service can claim campaigns and send their recipients for processing. |
campaign.dispatcher.poll-ms |
1000 ms |
CAMPAIGN_DISPATCHER_POLL_MS |
Delay after one campaign dispatch run finishes before the next run starts. |
campaign.dispatcher.campaign-batch-size |
10 |
CAMPAIGN_DISPATCHER_CAMPAIGN_BATCH_SIZE |
Maximum number of campaigns claimed in one dispatch run. |
campaign.dispatcher.recipient-batch-size |
999 |
CAMPAIGN_DISPATCHER_RECIPIENT_BATCH_SIZE |
Maximum number of recipients claimed for one campaign transaction. The default matches the promotional MNPSP limit. |
campaign.rollup.enabled |
true |
CAMPAIGN_ROLLUP_ENABLED |
Controls whether SMS recipient delivery results are copied to campaign recipient records. |
campaign.rollup.poll-ms |
2000 ms |
CAMPAIGN_ROLLUP_POLL_MS |
Delay after one delivery-result update run finishes before the next run starts. |
campaign.rollup.batch-size |
1000 |
CAMPAIGN_ROLLUP_BATCH_SIZE |
Maximum number of recipient records updated in one run. |
campaign.retry.enabled |
true |
CAMPAIGN_RETRY_ENABLED |
Controls whether recipients with temporary failures are made ready for another attempt. |
campaign.retry.poll-ms |
5000 ms |
CAMPAIGN_RETRY_POLL_MS |
Delay between checks for recipients that are ready to retry. |
campaign.retry.batch-size |
200 |
CAMPAIGN_RETRY_BATCH_SIZE |
Maximum number of recipients made ready again in one run. |
campaign.refund-retry.enabled |
true |
CAMPAIGN_REFUND_RETRY_ENABLED |
Controls whether the service retries refunds that have not been confirmed for recipients in a final state. |
campaign.refund-retry.poll-ms |
30000 ms |
CAMPAIGN_REFUND_RETRY_POLL_MS |
Delay between checks for refunds that are ready to retry. |
campaign.refund-retry.batch-size |
100 |
CAMPAIGN_REFUND_RETRY_BATCH_SIZE |
Maximum number of refunds claimed in one retry run. |
campaign.refund-retry.cooldown-minutes |
5 |
CAMPAIGN_REFUND_RETRY_COOLDOWN_MINUTES |
Minimum time a failed refund must wait before another attempt. |
Message speed depends on polling delays, batch sizes, available database connections, Kafka response time, and provider limits. Change one setting at a time. Monitor queued work, processing time, database connection use, and provider rate limits after each change.
Stale recovery, idempotency, and scheduler health¶
| Property | Default | Environment | Description |
|---|---|---|---|
campaign.stale.enabled |
true |
CAMPAIGN_STALE_ENABLED |
Controls whether the service finds and repairs campaigns that are stuck in an unfinished state. |
campaign.stale.poll-ms |
60000 ms |
CAMPAIGN_STALE_POLL_MS |
Delay between checks for stuck campaign work. |
campaign.stale.dispatch-grace-minutes |
10 |
CAMPAIGN_STALE_DISPATCH_GRACE_MINUTES |
Time a dispatch can remain unchanged before the service tries to recover it. |
campaign.stale.cancelling-grace-minutes |
10 |
CAMPAIGN_STALE_CANCELLING_GRACE_MINUTES |
Time a campaign can remain in CANCELLING before the service tries to finish the cancellation. |
campaign.stale.cancelling-batch-size |
50 |
CAMPAIGN_STALE_CANCELLING_BATCH_SIZE |
Maximum number of stuck cancellations handled in one recovery run. |
campaign.stale.draft-grace-minutes |
15 |
CAMPAIGN_STALE_DRAFT_GRACE_MINUTES |
Time a campaign can remain in DRAFT before its reserved balance is reversed and the campaign is marked as failed. |
campaign.stale.draft-batch-size |
50 |
CAMPAIGN_STALE_DRAFT_BATCH_SIZE |
Maximum number of stuck draft campaigns handled in one recovery run. |
campaign.stale.building-grace-minutes |
45 |
CAMPAIGN_STALE_BUILDING_GRACE_MINUTES |
Time a campaign can remain in BUILDING before recovery starts. Keep this longer than the build reclaim time. |
campaign.stale.building-batch-size |
50 |
CAMPAIGN_STALE_BUILDING_BATCH_SIZE |
Maximum number of stuck campaign builds handled in one recovery run. |
idempotency.purge.enabled |
true |
IDEMPOTENCY_PURGE_ENABLED |
Controls whether expired request replay records are deleted. |
idempotency.purge.poll-ms |
3600000 ms |
IDEMPOTENCY_PURGE_POLL_MS |
Delay between cleanup runs. The replay period is fixed in code at 24 hours. |
scheduler.health.startup-grace-seconds |
180 |
SCHEDULER_HEALTH_STARTUP_GRACE_SECONDS |
Time after startup when missing scheduler locks do not make the health check fail. |
Set building-grace-minutes higher than campaign.bulk.build.stale-minutes. Otherwise, recovery can fail a build before another builder is allowed to claim it.
Encryption and caches¶
| Property | Default | Environment | Description |
|---|---|---|---|
jasypt.encryptor.password |
dev-only-jasypt-master-key |
JASYPT_ENCRYPTOR_PASSWORD |
Master password used to encrypt and decrypt configuration and database values. Replace the development value outside local development. |
jasypt.encryptor.algorithm |
PBEWITHHMACSHA512ANDAES_256 |
JASYPT_ENCRYPTOR_ALGORITHM |
Algorithm used to encrypt and decrypt protected values. |
jasypt.encryptor.iv-generator-classname |
org.jasypt.iv.RandomIvGenerator |
JASYPT_ENCRYPTOR_IV_GENERATOR_CLASSNAME |
Class that creates a random initialization vector for each encrypted value. |
Routing caches can hold up to 5,000 entries for ten minutes. The client DLR setting uses a separate cache that holds up to 10,000 clients for 60 seconds. If the router cannot load a client's configuration, it does not cache the failure and keeps DLR enabled for safety.