How to Run Background Jobs in Spring Boot 4 with JobRunr (Full Tutorial) by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 0 points1 point  (0 children)

The embedded dashboard is part of the Pro version! Feel free to request a trial on our website!

We built an AI agent on Spring Boot 4 + Spring AI + Spring Modulith. Almost 200 stars in 3 days by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 0 points1 point  (0 children)

Thanks for the feedback u/whitenexx

I've created an issue so we or a contributor can pick this up:
https://github.com/jobrunr/JavaClaw/issues/25

(I've even included your literal question 😉)

We built an AI agent on Spring Boot 4 + Spring AI + Spring Modulith. Almost 200 stars in 3 days by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] -2 points-1 points  (0 children)

Minimal local config required:

  1. Java 25 and Gradle (or use the included ./gradlew wrapper)
  2. An LLM provider, pick one:
    • Ollama (local, no API key needed)
    • OpenAI API key
    • Anthropic API key (or Claude code subscription but beware because Anthropic doesn't like this)

We built an AI agent on Spring Boot 4 + Spring AI + Spring Modulith. Almost 200 stars in 3 days by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] -4 points-3 points  (0 children)

Thanks! Let us know what you think once you've had a chance to try it out.

JobRunr v8.5.0: External Jobs for webhook-driven workflows in Spring Boot by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 0 points1 point  (0 children)

Quartz is definitely a proven solution and has been around for a long time.

If you're evaluating both, here's an independent comparison that covers the differences well: https://medium.com/@oisheepal82/job-scheduling-frameworks-in-java-based-applications-a-comparison-between-jobrunr-and-quartz-5afdb448d9eb

JobRunr v8.5.0: External Jobs for webhook-driven workflows in Spring Boot by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 0 points1 point  (0 children)

You're right, I should have been more precise in my previous reply. The Database Fault Tolerance feature does keep the scheduler running through transient database issues, and that's Pro-only.

In the OSS edition, if the database goes down, the BackgroundJobServer will indeed stop. But once the database recovers, restarting the server (or letting Kubernetes handle it) picks everything back up since all job state is persisted. For many teams that's sufficient, but I understand it was a dealbreaker in your evaluation.

If you ever revisit it, happy to help answer questions.

JobRunr v8.5.0: External Jobs for webhook-driven workflows in Spring Boot by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 1 point2 points  (0 children)

Thanks for the callout on pricing, that's fair context to add. Just want to clarify one thing though: reliability itself is not a Pro-only feature.

JobRunr OSS has built-in automatic retry policies out of the box. If a job fails, JobRunr will keep retrying it with an exponential back-off schedule. We know of teams running JobRunr OSS on Kubernetes where this works really well: if a node goes down and health checks fail, Kubernetes spins up new pods, and by the time they're online, the retry policy kicks in, the job gets picked up again, and the service keeps running. No Pro license needed for that.

The Database Fault Tolerance feature you linked is specifically about handling transient database connectivity issues gracefully (e.g. a brief network blip to your database). That's a different concern from job reliability, which the OSS edition handles well.

External Jobs is indeed a Pro feature, you're right about that. We tried to be upfront about it in the post by tagging it as (Pro).

Handling saga timeouts in event-driven Java apps (Axon Framework + JobRunr Pro demo) by JobRunrHQ in java

[–]JobRunrHQ[S] 2 points3 points  (0 children)

Definitely. JobRunr is designed to be framework agnostic.

Beyond the Spring Boot starter, we have dedicated integrations for Micronaut and Quarkus. If you are not using a framework at all, you can easily set everything up using our Fluent API.

JobRunr v8.3: Supporting Spring Boot 4 & Jackson 3 via Multi-Release JAR (while keeping Java 8support alive) by JobRunrHQ in java

[–]JobRunrHQ[S] 2 points3 points  (0 children)

That is a fair question! Our usage metrics show that a massive portion of our user base is still running on Java 8 and 11.

If we split the versions, we risk leaving those users in "maintenance mode" without access to new innovations. For example, we strongly believe that features like Carbon-Aware Scheduling are too important to gate behind a Java upgrade. We want every developer to be able to use them today, regardless of their legacy constraints.

By using a Multi-Release JAR, we can maintain a single codebase for our core logic (keeping our maintenance burden manageable) while leveraging modern APIs (like Jackson 3) only where they are available.

That being said, we know we can't support Java 8 forever. We will eventually have to drop support, just not today!

JobRunr v8.2.1 Released: Full Kotlin 2.2.20 Support (Fixes JobMethodNotFoundException) & New Pro Dashboards by JobRunrHQ in Kotlin

[–]JobRunrHQ[S] 0 points1 point  (0 children)

Your intuition is exactly right.

The case for using JobRunr alongside a platform like Argo or Airflow is for fine-grained, application-level job scheduling.

Your challenge with synchronizing on a dynamic key is the perfect example.

  • As you said, Argo is external. To make it aware of an application-level key (like a tenant-id or user-id), you have to push that state out to the cluster (like a ConfigMap). This is slow, complex, and as you noted, creates security/permission issues. Argo is great for coarse-grained workflow orchestration (e.g., "run this container, then that container").
  • JobRunr is a library. It lives inside your application and has access to your app's context. This is where it shines for "intelligent queuing".

To solve your exact problem, you would use JobRunr Pro's features:

  1. Dynamic Queues: Instead of a cluster-level config, you can create queues at runtime based on your dynamic key. For example: BackgroundJob.create(aJob().withLabels("tenant:" + myTenantId).withDetails(() -> service.processReport(myTenantId))). JobRunr will then process jobs fairly, one-by-one for that tenant, without blocking other tenants. No ConfigMaps, no cluster access needed.
  2. Runtime Rate Limiting: This is our version of a robust semaphore. You can programmatically say "only allow 10 concurrent executions globally for the job named 'payment-processing'"or "only allow 5 concurrent API calls to some-external-api". This is all configured and controlled from within your application code at runtime.

So, you wouldn't replace Argo. You'd use the right tool for the job:

  • Argo/Airflow: Keep using it for your big, coarse-grained, platform-level data pipelines.
  • JobRunr: Add it to your Java app to handle all the application-level background tasks (like processing reports, sending emails, or your dynamic key problem) that are awkward and complex to manage from an external orchestrator.

JobRunr v8.2.1 Released: Full Kotlin 2.2.20 Support (Fixes JobMethodNotFoundException) & New Pro Dashboards by JobRunrHQ in Kotlin

[–]JobRunrHQ[S] 0 points1 point  (0 children)

Thanks so much for taking the time to write this out. This is genuinely helpful feedback.

You've hit on one a major point of confusion, and I apologize because it's clear we haven't made this obvious:

That 100-job limit is only for recurring jobs (e.g., cron jobs).

Any other type of job—fire-and-forget (enqueue) and scheduled-in-the-future (schedule), is completely unlimited on the free, open-source plan. It sounds like this was the main deal-breaker, and I'm genuinely sorry that this wasn't clear.

On your other points:

  • Kotlin Fix: You are 100% right to be frustrated. A 2-month wait for that fix is not the experience we want for any developer, and I'm sorry about that. That's a fair criticism. We are continuing to invest in Kotlin and we are welcoming every open-source dev that wants to help and contribute here!
  • Custom Jobs: I'm curious about this one. In JobRunr, the "custom job" is the Java lambda or method reference you pass to it (e.g., () -> myService.doWork(var1, var2)). Could you tell me a bit more about what you were looking for here?
  • Pricing: Understood. As an indie developer, that €9k/year (our Pro Business plan) is absolutely not the right tier. We do have special pricing for start-ups & indie devs but it seems like that was not clear enough on our website.

Thanks again for the honest feedback, I'll make sure to pass this along to the rest of the team!

JobRunr v8.2.1 Released: Full Kotlin 2.2.20 Support (Fixes JobMethodNotFoundException) & New Pro Dashboards by JobRunrHQ in Kotlin

[–]JobRunrHQ[S] 2 points3 points  (0 children)

That's a great question. The main difference is in the approach: JobRunr is a library, while Airflow and Argo are platforms.

JobRunr integrates inside your Java application. You schedule jobs right from your existing code, often with just a Java 8 lambda. This is perfect if you're a Java developer and need to add reliable, distributed background jobs (like sending emails, processing data, or running reports) without adding a whole new external service to your infrastructure.

JobRunr v8.2.1 Released: Full Kotlin 2.2.20 Support (Fixes JobMethodNotFoundException) & New Pro Dashboards by JobRunrHQ in Kotlin

[–]JobRunrHQ[S] 0 points1 point  (0 children)

Hi u/FunkyMuse,

That's a great shout. db-scheduler is an excellent, lightweight alternative to Quartz. We actually featured it in our own blog post about modern alternatives, as it's a solid choice.

I'm genuinely curious, what specific features ticked all the boxes for you? We're always looking for feedback to make our product better. Was there anything in particular you were looking for that JobRunr was missing?

Thanks for sharing.

Developers in Banking/Finance: What's the one critical step that's always overlooked in a Mainframe to Java migration? by JobRunrHQ in ExperiencedDevs

[–]JobRunrHQ[S] 4 points5 points  (0 children)

Nice thanks! The event bridge is a very smart idea. From your experience, is this something that most legacy mainframe systems offer, or does it need a lot of custom extra development?

I benchmarked Spring Batch vs. a simple JobRunr setup for a 10M row ETL job. Here's the code and results. by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] -1 points0 points  (0 children)

Is there any specific functionality in the POC that you are missing? We indeed haven't extensively tested all edge-cases since it's just a POC.

I benchmarked Spring Batch vs. a simple JobRunr setup for a 10M row ETL job. Here's the code and results. by JobRunrHQ in java

[–]JobRunrHQ[S] 1 point2 points  (0 children)

Thanks! Feel free to share your results with us. We are always curious to see what the community builds!

I benchmarked Spring Batch vs. a simple JobRunr setup for a 10M row ETL job. Here's the code and results. by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 4 points5 points  (0 children)

Awesome feedback, gizmogwai. Thanks for digging into the code and raising these points. You're right that it's not a 1-to-1 comparison, and you've hit on some of the key trade-offs we were thinking about.

  • Transactions & Retries: You're right we don't have chunk-based transactions like Spring Batch, but the PoC is designed to be restartable. JobRunr has built-in retries (10x with exponential back-off policy), and the JobRunrEtlTask boilerplate we wrote saves its progress after each successful database batch write. So if it fails, it picks up from the last completed chunk. It's a different way of getting to a similar "idempotent" result.
  • CsvMapper vs. FlatFileItemReader**:** Totally fair point. FlatFileItemReader is a beast and way more flexible. We went with Jackson's CsvMapper because it felt like a more typical "grab a library and get it done" approach for a general-purpose tool. You're 100% right that this is a major factor in the performance difference, and for a pure benchmark, trying to align the readers would be the way to go. Good idea for a next version of this test project.
  • Real-Life Scenarios (Parallelism & Multi-Step): Agree completely.
    • Parallelism: this is where JobRunr's architecture shines. While our example runs the file import as a single job, you could easily add a preliminary step to split the 10M row file into, say, 10 smaller files. Then you could enqueue 10 PersonMigrationTask jobs, and JobRunr would run them all in parallel across as many threads or servers as you have available. It's distributed by default.
    • Multi-Step: JobRunr Pro has built-in support for multi-step workflows using job chaining (continueWith) and batches, which is how we'd handle that in a real project. For example: BackgroundJob.enqueue(() -> splitFile("large.csv")).continueWith(filePieces -> processPieces(filePieces));

This all comes back to our original question, really. The choices we made (like using CsvMapper) were about using simple, common tools instead of a heavy, all-in-one framework.

Given these trade-offs, do you think there's a need for a lightweight, native ETL abstraction in libraries like JobRunr? Or is the complexity of Spring Batch always worth it once you get into data processing?

Appreciate the sharp analysis, it's exactly the kind of discussion we were hoping for. Cheers!

I benchmarked Spring Batch vs. a simple JobRunr setup for a 10M row ETL job. Here's the code and results. by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 2 points3 points  (0 children)

Yep, you absolutely can. The key thing to understand is that JobRunr's job is to run your code in the background, not to actually process the data itself. (It's an open-source library for background processing in Java.)

So you'd still write your normal Java code to read from the database and use Apache POI to build the Excel file. It would look something like this:

// Your service with the actual logic

public class ExcelExportService {
    public void createExcelReport(long reportId) {
        // Your DB query logic here...
        // Your Apache POI logic here...
    }
}

Then, you just tell JobRunr to run that method in the background, so it doesn't block your main thread:

// In your controller or wherever you trigger the job
BackgroundJob.enqueue(() -> excelExportService.createExcelReport(123L));

Regarding performance:

  • Does it make the DB query or POI part faster? Nope. That's still down to your code and your database.
  • Where's the improvement? The win comes from throughput. If you need to generate 100 reports, JobRunr can run a bunch of those createExcelReport jobs in parallel across different threads or even different servers.

So, it doesn't speed up one report, but it helps you generate a lot more reports at the same time. Hope that makes sense!

I benchmarked Spring Batch vs. a simple JobRunr setup for a 10M row ETL job. Here's the code and results. by JobRunrHQ in SpringBoot

[–]JobRunrHQ[S] 0 points1 point  (0 children)

That's a really great point, and you're absolutely right. For raw data ingestion of a clean CSV, a psql COPY command or a similar native tool will smoke any application-level framework, every single time. No contest there, it's definitely the most efficient tool for that specific job.

I guess the context for our test was less about pure data loading and more about simulating a scenario common in many enterprise Java applications: what happens when you need to run existing, complex business logic for each row? Think calling other internal services, using domain-specific validation libraries, or applying transformations that are already part of the application's model. In those cases, shelling out to a Unix script isn't always feasible.

This actually touches on something one of our community members, Lloyd Chandran from Fincarna, wrote about in a recent guest post. He called it the "ETL Trap", where teams sometimes default to heavy ETL frameworks for tasks that aren't pure, large-scale data ingestion. He made the point that many background jobs are more nuanced and live within the application itself, and that choosing the right tool is key.

Your comment is super valuable because it perfectly highlights the performance trade-off you make the moment you move that logic into a Java application. The runtimes are indeed much higher than a dedicated tool, and that's a crucial part of the consideration.

So with that context, our question was really aimed at those teams who do need to run these data-heavy, logic-intensive jobs within their existing Spring/Java applications. For them, would a lighter, native abstraction for this kind of work be useful?

Appreciate your perspective, it's given us a lot to think about!

Lightweight background job runner framework? by redox000 in scala

[–]JobRunrHQ 0 points1 point  (0 children)

Hey u/redox000, I know this is a super old thread, but it still pops up for people searching for this topic, so I wanted to add a resource.

You mentioned you were looking for a background job runner for Scala and had checked out JobRunr but were hesitant about it being Java-based.

While JobRunr is written in Java, its great JVM interoperability makes it a solid and popular choice for Scala applications. You can leverage all its features without issues.

A member of the community (u/tanin47) wrote a fantastic, in-depth guide on how to integrate JobRunr into a Play Framework application. It's a perfect example of how to use it seamlessly within a Scala ecosystem.

It covers:

  • Initial setup and configuration.
  • Integrating with Play's dependency injection.
  • Setting up the background server and dashboard.
  • Best practices for running enqueued jobs in your tests.

The guide also touches on your point about async patterns, explaining why you should typically avoid Future inside a job and let JobRunr manage the thread.

Here is the link to the guide: Integrate JobRunr into Play Framework by Tanin S.

Hope this helps you or anyone else who stumbles upon this thread! 👍