Describe the bug
JobConfigurationServiceImpl.java uses raw thread creation via:
new Thread(() -> executeMissedTrigger(jobId, syncFrequency)).start();
(line 735) to execute missed job triggers asynchronously.
This call is executed inside a forEach loop over all active sync jobs, meaning a new unmanaged thread is spawned for every job during application startup or missed-trigger recovery operations. Because these threads are created outside any managed ExecutorService or Spring-managed thread pool, the application has no mechanism to:
- Limit the number of concurrent threads
- Monitor or observe running threads
- Gracefully shut down threads during application exit
- Handle and propagate exceptions properly
- Reuse threads efficiently
Under heavy load, large job configurations, or repeated application restarts, this can lead to uncontrolled thread growth and potential JVM resource exhaustion. Additionally, unhandled exceptions inside these anonymous threads may be silently swallowed without centralized logging or recovery.
To Reproduce
Steps to reproduce the behavior:
- Configure multiple active sync jobs in the Registration Client database.
- Stop the application long enough for several scheduled triggers to be missed.
- Launch the Registration Client.
- During startup, observe that one raw thread is spawned per missed job trigger.
- Repeatedly restart the application or invoke
executeMissedTriggers().
- Monitor JVM thread count using JConsole, VisualVM, or thread dumps.
- Observe increasing numbers of unmanaged anonymous threads.
Expected behavior
Missed trigger executions should be submitted to a managed ExecutorService (such as a bounded/fixed thread pool) or use Spring's @Async support with a configured TaskExecutor.
This would ensure:
- Bounded thread creation
- Controlled concurrency
- Proper lifecycle management
- Graceful shutdown handling
- Centralized exception logging and recovery
- Better resource utilization through thread reuse
Screenshots
N/A (Backend threading issue — observable through JVM monitoring tools such as JConsole or VisualVM)
Environment:
- Server OS: N/A
- Client OS : macOS
- Build : master branch
- Browser : N/A (Desktop Application)
Attach logs
No direct exception is typically thrown.
Observable via thread dump showing large numbers of anonymous threads:
"Thread-42" #42 prio=5 os_prio=0 tid=0x... nid=0x... runnable
"Thread-43" #43 prio=5 os_prio=0 tid=0x... nid=0x... runnable
"Thread-44" #44 prio=5 os_prio=0 tid=0x... nid=0x... runnable
...
Additional context
The problematic code exists in JobConfigurationServiceImpl.java around Line 735:
new Thread(() -> executeMissedTrigger(jobId, syncFrequency)).start();
This logic is executed inside a loop iterating over all active sync jobs. As a result, the number of unmanaged threads created is directly proportional to the number of configured jobs, with no upper bound or throttling mechanism.
Describe the bug
JobConfigurationServiceImpl.javauses raw thread creation via:(line 735) to execute missed job triggers asynchronously.
This call is executed inside a
forEachloop over all active sync jobs, meaning a new unmanaged thread is spawned for every job during application startup or missed-trigger recovery operations. Because these threads are created outside any managedExecutorServiceor Spring-managed thread pool, the application has no mechanism to:Under heavy load, large job configurations, or repeated application restarts, this can lead to uncontrolled thread growth and potential JVM resource exhaustion. Additionally, unhandled exceptions inside these anonymous threads may be silently swallowed without centralized logging or recovery.
To Reproduce
Steps to reproduce the behavior:
executeMissedTriggers().Expected behavior
Missed trigger executions should be submitted to a managed
ExecutorService(such as a bounded/fixed thread pool) or use Spring's@Asyncsupport with a configuredTaskExecutor.This would ensure:
Screenshots
N/A (Backend threading issue — observable through JVM monitoring tools such as JConsole or VisualVM)
Environment:
Attach logs
No direct exception is typically thrown.
Observable via thread dump showing large numbers of anonymous threads:
Additional context
The problematic code exists in
JobConfigurationServiceImpl.javaaround Line 735:This logic is executed inside a loop iterating over all active sync jobs. As a result, the number of unmanaged threads created is directly proportional to the number of configured jobs, with no upper bound or throttling mechanism.