How are exceptions handled in #Cacheable method that uses sync=true - spring-boot

I am using #Cacheable in Spring Boot 2.0 with EHcache, with sync=true.
I understand that if we set sync=true, all threads wait until one thread fetches the value to cache by executing the method that used #Cacheable.
What happens if there is an exception in that method? Do the other threads keep waiting or is the lock released?

The idea of the #Cacheable annotation is that you use it to mark the
method return values that will be stored in the cache.
Each time the
method is called, Spring will cache its return value after it is called
to ensure that the next time the method is executed with the same
parameters, the result can be obtained directly from the cache without
the need to execute the method again. Spring caches the return value
of a method with key-value pairs. The value is the return result of
the method.
Now coming to your question, lets first understand what is Synchronized Caching
Synchronized Caching
In a multi-threaded environment, certain operations might be
concurrently invoked for the same argument (typically on startup). By
default, the cache abstraction does not lock anything, and the same
value may be computed several times, defeating the purpose of caching.
For those particular cases, you can use the sync attribute to instruct
the underlying cache provider to lock the cache entry while the value
is being computed. As a result, only one thread is busy computing the
value, while the others are blocked until the entry is updated in the
cache
The sole purpose of sync attribute is that only one thread will build the cache and other will consume the cache. Now if there is an exception during execution of method, which means the thread which acquired the lock will never set anything in cache and exit, now next thread will get it's chance to get lock because nothing would be there in cache, and if during second thread's execution exception occurs, then next thread will get it's chance until one threads sets the cache for same parameters.

Related

Understanding the "lifespan" of context

I'm having a bit of trouble understanding the "lifespan" of context.
I'm receiving RPC requests, and storing the request ID using context.WithValue so that it can be used for logging. There is no deadline or timeout for context in my service.
One of the methods called by RPC pulls some data from the database, calls a goroutine to do some processing (not relevant to the client), sends a response, and the method returns. The goroutine could run for ~15 seconds after the method returns.
I log the request ID in the goroutine a few times, and so far it works fine, but is there a situation where context could be garbage collected, and unavailable when I try to use it? Or will go know to keep context around until my goroutine has completed?
This leads me to another question - I'm not using context.WithCancel, does this mean it will remain in memory indefinitely? I'd imagine after a while this could cause some performance issues.
A context is a glorified done channel. Depending on where the context comes from, determines how it should be reclaimed:
If you create a context (context.WithCancel etc.) ensure you reclaim it when the sub-task it represents completes (defer cancelfn() etc. ensure this happens on API return).
If you are using a context from an external source (e.g.a gRPC request) - it's the responsibility of the API framework to close out the context.
go will reclaim any memory during GC as long as there are no active references (function closures etc.)

Ehcache and CacheWriter (write-behind) relation

Suppose we have a Cache configured with a write-behind CacheWriter. Let's assume we put some object in the cache and later on the object is removed because of an eviction policy.
What's is guaranteed regarding writing? More precisely, is write() event guaranteed to happen for that object, even though it was removed before it "had a chance" to be written?
Thanks!
No, write() is not guaranteed to happen. In a write-behind case, all writes are stored in a queue while some background threads read from that queue to update the underlying SoR (System of Records, i.e.: your database). That queue can be read or modified by other threads concurrently reading or modifying the same cache.
For instance, if a put() happens on a certain key, write() enqueues the command. If before one of the background thread had the chance to consume the write command before remove() happens on that same key, the write command can be removed from the queue (note the 'can' here). There are other similar optimizations that can take place ('can' again), those can change and new ones can be added in any minor version as this is all considered an implementation detail, as long as the data served by Ehcache follows its general visibility guarantees.
This means Write-Behind, and more generally all CacheWriters must not be used for any form of accounting, if that's the use-case you had in mind.

Ehcache 3: Are keys that being written get locked?

Suppose we have a cache with a CacheLoaderWriter, so we are registered to the events: write and writeAll.
What is the status of these keys at that time?
i.e. If another thread tries to cache.get(keyThatBeingWritten), will it be blocked until the write()/writeAll() operations exit?
writeAll() logically functions like a succession of write(), it is entirely possible for one thread to observe some already written data while another thread is still busy executing writeAll().
Regarding write(), it will block concurrent reader and writer threads working on the same key if needed for as long as needed to fulfill the Ehcache visibility guarantees.

When to session.commit() in a NiFi Processor

I am implementing a NiFi processor and have couple of clarifications to make with respect to best practices:
session.getProvenanceReporter().modify(...) - Should we emit the event immediately after every session.transfer()
session.commit() - Documentation says, after performing operations on flowfiles, either commit or rollback can be invoked.
Developer guide: https://nifi.apache.org/docs/nifi-docs/html/developer-guide.html#process_session
Question is, what do I lose by not invoking these methods explicitly?
1) Yes typically the provenance event is emitted after transferring the flow file.
2) It depends if you are extending AbstractProcessor, or AbstractSessionFactoryProcessor. AbstractProcessor will call commit or rollback for you so you don't need to, AbstractSessionFactoryProcessor requires you to call them appropriately.
If you are extending AbstractSessionFactoryProcessor and never call commit, eventually that session will get garbage collected and rollback will be called, and all the operations performed by that session will be rolled back.
There is also an annotation #SupportsBatching which can be placed on a processor. When this annotation is present, the UI shows a slider on the processor's scheduling tab that indicates how many milliseconds worth of framework operations like commit() can be batched together behind the scenes for increased throughput. If latency is more important then leaving the slides at 0 milliseconds is appropriate, but the key here is that the user gets to decide this when building the flow and configuring the processor.

ActionServlet - Synchronized block - working of threads

if there is a synchronized block in the service() method of say for example in ActionServlet of struts, how will multiple requests/threads work if it is a busy site having large number of hits.
Will each thread wait for the next other one to release lock from the synchronized block? Will that create delay in response
Don't synchronize the service method of a servlet.
If you synchronize the service method of a servlet, you are in fact making a "reservation on access" for a thread at a time for that instance of the Servlet.
The Struts ActionServlet class is a HttpServlet and basically the doGet and doPost methods are of interest here. If we are to speak about Struts, the process method is the main entry point, but the same principle applies to all methods as it does for the general service method.
The idea is this.
When you declare a servlet in your web.app, the servlet container (e.g. Tomcat) will create only one instance of that servlet. This means there is only one instance to serve all requests.
If more requests arrive at the same time, each request thread gets it chance at the service method because there is no synchronization enforced.
If you have 10 request threads, each will execute concurrently in the service method. This is normally safe because processing done in the service method does not involve any state related to the current request it is handling. You go into issues if you add state to your servlets. Here is an article with more details on the subject.
Now back to Struts.
Struts uses a pattern called a Front Controller with the ActionServlet being that controller. This will in turn delegate specific requests to specific Action classes as specified in its configuration (a.k.a struts-config.xml).
All incoming request pass though here. If you place synchronization at this point (the Struts process method or the servlet service method higher up) you are reserving the servlet for a thread at a time. In case of struts, you are reserving all processing of a request to a single thread at a time.
That means that if 10 request arrive simultaneousely, in the case without synchronization all can execute side by side, while in the case with synchronization request 2 will have to wait until request 1 is done, 3 waits for 2 and so on (i.e. requests are sequentially processed). And this means poor performance.
Maybe for the lucky user that made request 1 there will be no performance impact but number 10 will have to wait. Then how about number 100? 200?
There is no need to synchronize the entry point if you program your application with thread safety in mind. If your application is of the sort that you just can't avoid synchronization, then synchronizing the entry point will reduce performance.
P.S. Just one other thing. If you are thinking into moving the synchronization lower in the process, namely the Action classes, note that they are not thread safe either and there is only one instance of it inside the Struts framework.

Resources