<p>I'm coming from the PHP/Python/JS environment where it's a standard to run multiple instances of web application as separate processes and asynchronous tasks like queue processing as separate scripts.</p>
<p><strong>eg. in the k8s environment, there would be</strong></p>
<ul>
<li>N instances of <strong>web server only</strong>, each running in separate pod</li>
<li>For each queue, <strong>dynamic number of consumers, each in separate pod</strong></li>
<li><strong>Cron scheduling using k8s crontab</strong> functionality, leaving the scheduling process to k8s</li>
</ul>
<p>Such approach matches well the cloud nature where the workload can be scheduled across both smaller number of powerful machines and <strong>lot of less powerful machines</strong> and allows very fine control of auto scaling (based on the number of messages in specific queue for example).</p>
<p>Also, there is a clear separation between the developer and DevOps responsibility.</p>
<p>Recently, I tried to replicate the same setup with <strong>Java Spring Boot</strong> application and failed miserably.</p>
<p>Even though Java frameworks say that they are &quot;cloud native&quot;, it seems like all the documentation is still built around monolith application, which handles all consumers and cron scheduling in separate threads.</p>
<p>Clear answer to this problem is microservices but that's way out of scope.</p>
<p><strong>What I need is to deploy separate parts of application (like 1 queue listener only) per pod in the cloud yet keep the monolith code architecture.</strong></p>
<p>So, the question is:</p>
<p>How do I design my Spring Boot application so that:</p>
<ul>
<li>I can run the webserver separately without queue listeners and scheduled jobs</li>
<li>I can run one queue listener per pod in the k8s</li>
<li>I can use k8s cron scheduling instead of App level Spring scheduler?</li>
</ul>
<p>I found several ways to achieve something like this but I expect there must be some &quot;more or less standard way&quot;.</p>
<hr />
<p>Alternative solutions that came to my mind:</p>
<ul>
<li>Having separate module with separate Application definition so that each &quot;command&quot; is built separately</li>
<li>Using Spring Profiles to instantiate specific services only according to some environment variables</li>
<li>Implement custom command line runner which would parse command name/queue name and dynamically create appropriate services (this seems to be the most similar approach to the way how it's done in &quot;scripting languages&quot;)</li>
</ul>
<p>What I mainly want to achieve with such setup is:</p>
<ul>
<li>To be able to run the application on lot of weak HW instead of having 1 machine with 32 cpu cores</li>
<li>Easier scaling per workload</li>
<li>Removing one layer from already complex monitoring infrastructure (k8s already allows very fine resource monitoring, application level task scheduling and parallelism makes this way more difficult)</li>
</ul>
<p>Do I miss something or is it just that it's not standard to write Java server apps this way?
Thank you!</p>

olsavmic
<blockquote>
<p>What I need is to deploy separate parts of application (like 1 queue listener only) per pod in the cloud yet keep the monolith code architecture.</p>
</blockquote>
<p>I agree with <a href="https://stackoverflow.com/a/71598155/2446208">@jacky-neo's answer</a> in terms of the appropriate architecture/best practice, but that may require you to break up your monolithic application.</p>
<p>To solve this without breaking up your monolithic application, deploy multiple instances of your monolith to Kubernetes each as a separate <code>Deployment</code>. Each deployment can have its own configuration. Then you can <a href="https://www.baeldung.com/spring-feature-flags" rel="nofollow noreferrer">utilize feature flags</a> and define the environment variables for each deployment based on the functionality you would like to enable.</p>
<p>In <code>application.properties</code>:</p>
<pre><code>myapp.queue.listener.enabled=${QUEUE_LISTENER_ENABLED:false}
</code></pre>
<p>In your <code>Deployment</code> for the queue listener, enable the feature flag:</p>
<pre class="lang-yaml prettyprint-override"><code>env:
  - name: 'QUEUE_LISTENER_ENABLED'
    value: 'true'
</code></pre>
<p>You would then just need to configure your monolithic application to use this <code>myapp.queue.listener.enabled</code> property and only enable the queue listener when the property is set to <code>true</code>.</p>
<p>Similarly, you could also apply this logic to the Spring profile to only run certain features in your app based on the profile defined in your <code>ConfigMap</code>.</p>
<p><a href="https://www.baeldung.com/spring-feature-flags" rel="nofollow noreferrer">This Baeldung article</a> explains the process I'm presenting here in detail.</p>
<p>For the scheduled task, just <a href="https://florianbuchner.com/kubernetes-curl-cronjob-for-internal-service/" rel="nofollow noreferrer">set up a <code>CronJob</code> using a <code>curl</code> container</a> which can invoke the service you want to perform the work.</p>
<h2>Edit</h2>
<p>Another option based on your comments below -- split the shared logic out into a <code>shared</code> module (using Gradle or Maven), and have two other runnable modules like <code>web</code> and <code>listener</code> that depend on the <code>shared</code> module. This will allow you to keep your shared logic in the same repository, and keep you from having to build/maintain an extra library which you would like to avoid.</p>
<p>This would be a good step in the right direction, and it would lend well to breaking the app into smaller pieces later down the road.</p>
<p><a href="https://spring.io/guides/gs/multi-module/" rel="nofollow noreferrer">Here's some additional info</a> about multi-module Spring Boot projects using Maven or Gradle.</p>
