-
Notifications
You must be signed in to change notification settings - Fork 152
add APPLICATION_PROPERTIES env var for Spring Boot runtime tuning #762
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
WMP
wants to merge
1
commit into
mbentley:master
Choose a base branch
from
WMP:feature/application-properties-injection
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| # Spring Boot Tuning | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of putting this in a separate |
||
|
|
||
| The Omada Controller (v5.x and above) is built on [Spring Boot](https://spring.io/projects/spring-boot). | ||
| Its classpath includes `/opt/tplink/EAPController/properties`, which means Spring Boot will automatically | ||
| load an `application.properties` file placed there at startup. | ||
|
|
||
| The `APPLICATION_PROPERTIES` environment variable allows you to inject arbitrary Spring Boot properties | ||
| into the controller without rebuilding the image or overriding the `CMD`. | ||
|
|
||
| > [!WARNING] | ||
| > This is an unofficial tuning mechanism. TP-Link does not document or guarantee which | ||
| > Spring Boot properties are honoured. Settings listed here are best-effort based on the Spring Boot | ||
| > defaults for an embedded Tomcat server. Test in a non-production environment first. | ||
|
|
||
| --- | ||
|
|
||
| ## How to Use | ||
|
|
||
| Set `APPLICATION_PROPERTIES` to a newline-separated list of `key=value` pairs. The entrypoint writes | ||
| them verbatim to `/opt/tplink/EAPController/properties/application.properties` before the JVM starts. | ||
|
|
||
| ### Docker Compose | ||
|
|
||
| ```yaml | ||
| services: | ||
| omada-controller: | ||
| image: mbentley/omada-controller:6.2 | ||
| environment: | ||
| APPLICATION_PROPERTIES: | | ||
| server.tomcat.threads.max=50 | ||
| server.tomcat.threads.min-spare=5 | ||
| spring.task.execution.pool.max-size=10 | ||
| ``` | ||
|
|
||
| ### Docker CLI | ||
|
|
||
| ```bash | ||
| docker run \ | ||
| -e APPLICATION_PROPERTIES=$'server.tomcat.threads.max=50\nserver.tomcat.threads.min-spare=5' \ | ||
| mbentley/omada-controller:6.2 | ||
| ``` | ||
|
|
||
| ### Kubernetes / Helm (extraEnvVars) | ||
|
|
||
| ```yaml | ||
| extraEnvVars: | ||
| APPLICATION_PROPERTIES: | | ||
| server.tomcat.threads.max=50 | ||
| server.tomcat.threads.min-spare=5 | ||
| spring.task.execution.pool.core-size=5 | ||
| spring.task.execution.pool.max-size=10 | ||
| spring.task.scheduling.pool.size=3 | ||
| ``` | ||
|
|
||
| The startup log will confirm the file was written: | ||
|
|
||
| ``` | ||
| INFO: APPLICATION_PROPERTIES set; writing Spring Boot properties to /opt/tplink/EAPController/properties/application.properties | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Available Settings | ||
|
|
||
| ### Tomcat HTTP Thread Pool | ||
|
|
||
| Controls how many threads Tomcat uses to handle incoming HTTP/HTTPS requests. | ||
| The Omada web UI and API run through this pool. | ||
|
|
||
| | Property | Default | Description | | ||
| |---|---|---| | ||
| | `server.tomcat.threads.max` | `200` | Maximum number of worker threads. Reduce to limit memory usage. | | ||
| | `server.tomcat.threads.min-spare` | `10` | Minimum number of threads kept alive (idle). | | ||
| | `server.tomcat.accept-count` | `100` | Queue size for incoming connections when all threads are busy. | | ||
| | `server.tomcat.connection-timeout` | `20000` | Timeout (ms) for accepting a connection. | | ||
|
|
||
| **Typical constrained setup:** | ||
| ```properties | ||
| server.tomcat.threads.max=50 | ||
| server.tomcat.threads.min-spare=5 | ||
| server.tomcat.accept-count=50 | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Async Task Executor | ||
|
|
||
| Used for background tasks dispatched via Spring's `@Async` annotation — e.g. device | ||
| status polling, event processing. | ||
|
|
||
| | Property | Default | Description | | ||
| |---|---|---| | ||
| | `spring.task.execution.pool.core-size` | `8` | Threads always kept alive in the pool. | | ||
| | `spring.task.execution.pool.max-size` | `Integer.MAX_VALUE` | Maximum pool size. Set this explicitly. | | ||
| | `spring.task.execution.pool.queue-capacity` | `Integer.MAX_VALUE` | Task queue depth before new threads are spawned. | | ||
| | `spring.task.execution.pool.keep-alive` | `60s` | How long idle threads above core-size are kept. | | ||
| | `spring.task.execution.thread-name-prefix` | `task-` | Thread name prefix (useful for profiling). | | ||
|
|
||
| **Typical constrained setup:** | ||
| ```properties | ||
| spring.task.execution.pool.core-size=5 | ||
| spring.task.execution.pool.max-size=20 | ||
| spring.task.execution.pool.queue-capacity=100 | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Scheduled Task Pool | ||
|
|
||
| Controls the thread pool for `@Scheduled` tasks — periodic jobs like cleanup, | ||
| health checks, and device discovery heartbeats. | ||
|
|
||
| | Property | Default | Description | | ||
| |---|---|---| | ||
| | `spring.task.scheduling.pool.size` | `1` | Number of scheduling threads. Rarely needs to exceed 3. | | ||
| | `spring.task.scheduling.thread-name-prefix` | `scheduling-` | Thread name prefix. | | ||
|
|
||
| **Typical setup:** | ||
| ```properties | ||
| spring.task.scheduling.pool.size=2 | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### Logging | ||
|
|
||
| Reducing log verbosity saves CPU and I/O, especially on slow storage (e.g. NFS-backed PVCs). | ||
|
|
||
| | Property | Default | Description | | ||
| |---|---|---| | ||
| | `logging.level.root` | `INFO` | Root log level. Set to `WARN` to reduce noise. | | ||
| | `logging.level.org.springframework` | `INFO` | Spring Framework log level. | | ||
| | `logging.level.org.mongodb` | `INFO` | MongoDB driver log level. | | ||
| | `logging.level.com.tplink` | `INFO` | Omada application log level. | | ||
|
|
||
| **Reduce verbosity:** | ||
| ```properties | ||
| logging.level.root=WARN | ||
| logging.level.com.tplink=INFO | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Example: Memory-Constrained Setup (Kubernetes, ≤ 2 GB pod limit) | ||
|
|
||
| This example targets a pod with `limits.memory: 2048Mi` running OpenJ9. | ||
| Combined with `JAVA_MAX_HEAP_SIZE=512m` and `MONGOD_EXTRA_ARGS=--wiredTigerCacheSizeGB 0.25`, | ||
| the approximate memory budget is: | ||
|
|
||
| | Component | Budget | | ||
| |---|---| | ||
| | Java heap (`-Xmx`) | 512 MB | | ||
| | Java metaspace + JIT code | ~150 MB | | ||
| | MongoDB WiredTiger cache | 256 MB | | ||
| | Tomcat threads × ~1 MB stack | ~50 MB | | ||
| | OS + JVM overhead | ~300 MB | | ||
| | **Total** | **~1.3 GB** | | ||
|
|
||
| ```yaml | ||
| extraEnvVars: | ||
| JAVA_MAX_HEAP_SIZE: "512m" | ||
| JAVA_MIN_HEAP_SIZE: "128m" | ||
| MONGOD_EXTRA_ARGS: "--wiredTigerCacheSizeGB 0.25" | ||
| APPLICATION_PROPERTIES: | | ||
| server.tomcat.threads.max=50 | ||
| server.tomcat.threads.min-spare=5 | ||
| server.tomcat.accept-count=50 | ||
| spring.task.execution.pool.core-size=5 | ||
| spring.task.execution.pool.max-size=20 | ||
| spring.task.execution.pool.queue-capacity=100 | ||
| spring.task.scheduling.pool.size=2 | ||
| logging.level.root=WARN | ||
| logging.level.com.tplink=INFO | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Notes and Limitations | ||
|
|
||
| - **Version requirement**: `APPLICATION_PROPERTIES` only works with v5.x and above (Spring Boot base). | ||
| On v4.x and below, the properties directory is not on the classpath and the file will be ignored. | ||
| - **File is regenerated on every start**: The file is written fresh from the env var each time the | ||
| container starts, so changes to `APPLICATION_PROPERTIES` always take effect on the next restart. | ||
| - **No conflict with `omada.properties`**: Spring Boot reads `application.properties` for its own | ||
| framework settings; Omada's application config lives in `omada.properties` (a different file). | ||
| - **Unknown properties are ignored**: Spring Boot will log a warning for unrecognised keys but will | ||
| not fail to start. | ||
| - **Property precedence**: Environment variables set directly on the container (e.g. | ||
| `SERVER_TOMCAT_THREADS_MAX=50`) have higher precedence than `application.properties` in the Spring | ||
| Boot relaxed-binding hierarchy. Both approaches work; `APPLICATION_PROPERTIES` is more explicit and | ||
| easier to manage as a block. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In non-rootless mode, the script runs as root at this point and gosu only executes at the very end. Double check my logic but the file is created owned by root:root with mode 640. The omada controller process (launched via exec gosu "${PUSERNAME}") is not in the root group, so it cannot read the file. Spring Boot will silently finds no application.properties and the feature does nothing.
So if I am right, the fix that would be easiest would probably be to add the same chown in inject_application_properties(), guarded for rootless.