Skip to main content

r/SpringBoot


Used ShedLock in production for few months now. Sharing my experience.
Used ShedLock in production for few months now. Sharing my experience.
Discussion

We have scheduled jobs in our Spring Boot services.

We was using spring bootScheduled annotationfor syncing data and sending notifications.

It worked fine when we had one instance but then we decided to scale to multiple pods and regions in openshift cloud platform, so using Scheduled will run the job on each pods.

We decided to go with Shedlock as it is small library and the idea is simple, before a job runs, it takes a lock in a shared store. If another pod already took the lock, the job just skips. For shared store, we used Couchbase as ShedLock has a Couchbase lock provider.

Few months in production now with zero duplicate runs, just take care of below two things.

First is that lockAtMostFor is important. If your pod dies mid job, this is how long the lock stays before another pod can pick it up. You can set it a bit longer than your worst case job time. And second is that ShedLock will not retry or re run missed jobs. It only makes sure at most one instance runs.

What other solution you have used for same problem?


Advertisement: Got a creative vision? Codex helps bring it to life. Try Codex for free today.
Got a creative vision? Codex helps bring it to life. Try Codex for free today.
media poster


8 @Transactional rules I follow after debugging too many production bugs
8 @Transactional rules I follow after debugging too many production bugs
Discussion

Been working with Spring Boot for 10+ years and I keep seeing the same Transactional bugs show up in code reviews and production incidents. Figured I'd share the rules I follow now.

  1. Keep transactions short. DB operations only. If your method calls an external API, sends an email, or uploads a file inside Transactional, it holds a DB connection for the entire duration. Not just during queries. During the ENTIRE method. Under load your connection pool runs out and your app freezes.

  2. Never call a Transactional method from the same class. Spring uses proxies. When you call a method within the same class its a direct this.method() call. Proxy is bypassed. The annotation is completely invisible. No warning. No error. It just does nothing.

  3. Use rollbackFor = Exception.class for critical operations. This one catches people off guard. Transactional only rolls back on RuntimeException by default. If your method throws a checked exception like PaymentException, the transaction commits. Your balance gets deducted but the payment never went through.

  4. Don't catch exceptions inside Transactional unless you re-throw. If you catch the exception, the proxy sees a normal return. It commits. Partial data in your database. Silent corruption. Either let it propagate, re-throw after logging, or call TransactionAspectSupport.currentTransactionStatus().setRollbackOnly().

  5. Use readOnly = true on all read-only methods. It tells Hibernate to skip dirty checking and snapshot comparison. Saves CPU and memory. Some proxies use it to route to read replicas. But don't rely on it to prevent writes. Explicit save() or flush() still goes through.

  6. Only works on public methods. Proxy can only intercept public methods. Put Transactional on a private method and it does absolutely nothing. Spring won't even warn you.

  7. Separate Retryable and Transactional into different beans. If both are on the same method and a checked exception is thrown, the transaction commits before the retry fires. Retry starts a new transaction. Same deduction runs again. Triple retry = triple deduction. Outer bean handles retry, inner bean handles transaction.

  8. Enable these two configs in every environment. logging.level.org.springframework.transaction.interceptor: TRACE shows when transactions start commit and rollback.

spring.datasource.hikari.leak-detection-threshold: 15000 catches connections held too long with a full stack trace.

The one rule that covers most of these: uTransactional only works on public methods called from outside the bean. Everything else is silently ignored.

Anyone run into other Transactional gotchas I missed?


How do you plan, learn, and deploy system architecture? (Beginner looking for advice)
How do you plan, learn, and deploy system architecture? (Beginner looking for advice)
Question

Hey everyone, I'm just starting to learn system architecture and would love to hear how experienced folks approach it. How do you plan a system when starting a new project — do you sketch diagrams first, follow a methodology, or just iterate? Also do you approach it to production? Thanks in advance!