How to maintain state in autowired webservices? - java

I have a design problem as follows: I want to execute several soap webservices, where each response depends on the former.
When all responses are obtained, I want to validate all obtained data, then build some output based on it, and also issue from DB update.
Therefore I created a TemplateFacade method that wrapps all webservices that are to be executed. Problem: I obviously have to persist the responses between the method calls. Which will be problematic as autowired services should by definition be stateless and are singletons.
So how can I use injection with services that have to maintain some kind of state (at least until the Executor.execute() has terminated)?
Could you recommend a better design approach?
#Component
class Executor {
#Autowired
TemplateFacade template;
public void execute() {
template.run();
template.validate();
template.buildOutput();
template.updateDatabase();
}
}
#Service
class TemplateFacade {
//service classes wrapping webservice soap execution logic
#Autowired
PersonSoap personSoap;
#Autowired
CarSsoap carSoap;
#Autowired
ServiceDao dao;
private WebserviceRsp personRsp, carRsp;
void run() {
personRsp = personSoap.invoke();
//process response and prepare CarSoapXML accordingly, then send
carRsp = carSoap.invoke();
}
//the following methods will all
void validate() {
//validate both responses
}
void buildOutput() {
//create system out based on responses
}
void updateDatabase() {
dao.update(..);
}
}

To share state between multiple web services, you could keep track using a PersonState in the session which is tied to the user. I recommend encryption or hashing to secure the information.
When the validate completes, you could keep a PersonState in the session. When the buildOutput starts, you could get the PersonState object and continue with your logic and so on.
It is important that, you keep the PersonState to have a smaller memory footprint. Incase of a lot of data, you could just create a stateObject that will have the necessary state for the next step. e.g. at the end of validate you could create, BuildState object and put it in the session. build will get the object from the session and continue.
But I am not sure if it is really necessary to keep track of state and do it in 2 web services calls. The better solution would be to move all the logic part to another layer, and use the web services as just a window to your business/process layer.
Edit:
One more solution that could work you, is that the response of each step could contain the necessary state that is required for the next step. e.g. validateResponse contains personState and that could somehow be passed for the build.

Related

Spring Cache Error Handler - Send a Response back on CacheEvict Error

I am working on a fallback procedure for when the connection fail (or another error) occurs. I've created the CacheConfiguration/CacheErrorHandler to handle the errors and log them. The application successfully switches between using the cache and going through the normal process when Redis fails.
However, the way I've implemented cache eviction endpoint (via the #cacheEvict annotation), it is essentially an empty method.
#DeleteMapping(value = "/cache/clear")
#CacheEvict(value = {_values_}, allEntries = true)
public ResponseEntity<String> clearAllCache() {return ResponseEntity.ok("OK"); }
Current CacheErrorHandler
#Override
public CacheErrorHandler errorHandler() {
return new CacheErrorHandler() {
#Override
public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
LOGGER.warn("Failure evicting from cache: " + cache.getName() + ", exception: " + exception);
}
}
Logger will output the cacheEvictError but the response will send back "OK" to the client.
Is there a way to catch the cache error and send a different response saying that the cache evict failed?
I've tried adding a try-catch to throw an exception inside the endpoint but that went nowhere. Couldn't seem to find any examples online to solve this specific issue.
One thing to keep in mind here is that Spring's #CacheEvict annotation and behavior is called "after" the method (by default) on which the annotation is declared, which in your case is the clearAllCache() Web service method.
Although, you can configure the cache eviction to occur before the (actual) clearAllCache() Web service method is called, like so:
#CacheEvict(cacheNames = { ... }, allEntries = true, beforeInvocation = true)
public ResponseEntity<String> clearAllCache() {
// ...
}
That is, using the beforeInvocation attribute on the #CacheEvict annotation, set to true, the cache eviction (for all entries) will occur before the actual clearAllCache() method is invoked.
NOTE: Logically, if the invocation happens after the clearAllCache() method has already been called, then you really have no way to respond if the cache eviction (or rather, the "clear" operation) was unsuccessful. So you must configure the cache eviction to occur before your Web service method gets invoked, first of all.
Next, you need someway to know that your custom CacheErrorHandler was invoked on an error occurring in your caching provider (e.g. Redis) during eviction (or technically, the Cache.clear() operation in this case, since you evicting "all entries").
Another thing to keep in mind here is that since you appear to be operating in Web environment (e.g. a Servlet container like Tomcat or Jetty, or other) then you need to keep "Thread Safety" in mind since each HTTP request and corresponding Web handler method, like the clearAllCache() method called on HTTP DELETE, will be invoked from a separate Thread (i.e. Thread per (HTTP) Request model).
So, you can solve that problem using a Java ThreadLocal declared inside your custom CacheErrorHandler class to capture the necessary state / information that is needed once the clearAllCache() method is called.
I have wrote one such example test class demonstrating how you could accomplish this. The key to this implementation (solution) is the proper configuration of the cache eviction and the use of the ThreadLocal in the custom CacheErrorHandler.
My test is not specifically configured as a Web-based service (e.g. using Spring Web MVC, or anything like that), but I modeled the test use case after your particular situation. I also made use of Mockito to spy on the Spring caching infrastructure to always throw a RuntimeException anytime a Cache eviction based operation occurs (e.g. evict(key) or clear(), etc).
Of course, there are probably better, more robust ways to implement this solution, but this at least demonstrates that it is possible.
Hopefully, this gives you more ideas.

how to make spring boot rest api as stateful

I want to make web application with REST and spring boot. Rest web service is stateless. I want to make it stateful so that the information server send to client after first request should be used in upcoming request. Or the execution done in first or second request will be used further.
Can we generate some session id for this and this session id client can send to sever in followed requests ? If yes, then
if state is changing (values get modified due to some manipulation) of some objects/beans. So how can we save the state inorder of objects/beans to make it stateful and what is the scope of these beans (whose value will be modified) and those classes/beans which will give call to these beans as multiple clients or users will be using this web application ?
Restful API's are not stateful by design, if you make them stateful using a server side then its not REST!
What you need a correlation Id which is a recognised pattern in a distributed system design. Correlation Id will let you tie requests together.
Sessions are typically an optimization to improve performance when running multiple servers. They improve performance by ensuring that a clients requests always get sent to the same server which has cached the clients data.
If you only want to run a single server, you won't have to worry about sessions. There are two common approaches to solve this problem.
1. In Memory State
If the state you want to maintain is small enough to fit into memory, and you don't mind losing it in the event of a server crash or reboot, you can save it in memory. You can create a spring service which holds a data structure. Then you can inject that service into your controllers and change the state in your http handlers.
Services are singletons by default. So state stored in a service is accessible to all controllers, components, and user requests. A small pseudo example is bellow.
Service Class
#Service
public class MyState
{
private Map<String, Integer> sums = new HashMap<>();
public synchronized int get(String key) {
return sums.get(key);
}
public synchronized void add(String key, int val) {
int sum = 0;
if (sums.contains(key)) {
sum = sum.get(key);
}
sum += val;
sums.put(key, (Integer)sum);
}
}
Controller Class
#RestController
#RequestMapping("/sum")
public class FactoryController
{
#Autowired
private MyState myState;
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
#ResponseBody
public SuccessResponse saveFactory(#RequestBody KeyVal keyVal)
{
myState.add(keyVal.getKey(), keyVal.getValue());
}
}
Note: This approach will not work if you are running multiple servers behind a load balancer, unless you use a more complex solution like a distributed cache. Sessions can be used to optimize performance in this case.
2. Database
The other option is to just use a database to store your state. This way you won't lose data if you crash or reboot. Spring supports the hibernate persistence framework and you can run a database like Postgres.
Note: If you are running multiple servers you will need a more complex solution since hibernate caches data in memory. You will have to plug hibernate into a distributed cache to synchronize in memory state across multiple servers. Sessions could be used as a performance optimization here.
Important
Whenever you are modifying state you need to make sure you are doing it in a thread safe manner, otherwise your state may be incorrect.

Guice Request Scope for tracing workflow of request

I have a use case where I have 6 steps being performed in one request. The business is requesting that we capture metrics on what the result of each step was in the process. They want us to log to a Kinesis stream.
Architecturally I am looking at the best solution. We have java based services I want to have a request scoped object enriched as the request progresses, then when the endpoint finishes we would make a service call to kinesis asynchronous using a fire and forget pattern. This way the reporting is not holding up the main thread.
I was looking at using the raw ThreadLocal or guice scope. Has anyone ran into to a similar problem that they solved? Im thinking of use guice request scoped components, which will greatly simply the code. Just looking for some opinions. Thanks!
I'm assuming you aren't on a servlet environment because, then, you will just use the built in request scope. Even then you can use the request scope from guice-servlet building the scope yourself.
void processRequest() {
RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap());
try ( RequestScoper.CloseableScope ignored = scope.open() ) {
step1();
step2();
step3();
step4();
step5();
step6();
}
}
You can use #RequestScoped and it will be the same object on all your steps. You can, for example, use a provider to get access to it.

Jersey #ManagedAsync and copying data between HTTP thread and Worker thread

I am working on a project that works in two flavors with and without multi tenancy.
The project exposes a REST service which I would like to be asynchronous.
So my basic service looks like
#Component
#Path("/resouce")
#Consumes(MediaType.APPLICATION_JSON)
public class ResouceEndpoint {
#POST
#ManagedAsync
public void add(final Event event, #Suspended final AsyncResponse asyncResponse) {
resouce.insert (event);
asyncResponse.resume( Response.status(Response.Status.NO_CONTENT).build());
}
}
That works fine without multi tenancy and I get the benefits of the internal Jersey executor service for free. See #ManagedAsync
When I switch to multi tenancy I add a filter on the request that resolve the tenant id and place it on the thread local (in our case the HTTP thread).
When the processing chain hits the "add()" method above the current thread is the one provided by the Jersey executor service, so it does not include my tenant id.
I could think only on the following options to work around this issue.
Extend the ResouceEndpoint to MutliTenantResouceEndpoint and drop the #ManagedAsync
Using my own thread executor
public class MutliTenantResouceEndpoint extends ResouceEndpoint {
#POST
public void add(final Event event, #Suspended final AsyncResponse asyncResponse) {
final String tenantId = getTeantIdFromThreadLocal();
taskExecutor.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
setTeantIdToThreadLocal(tenantId);
browserEventsAnalyzer.insertEvent(event);
Response response = Response.status(Response.Status.NO_CONTENT).build();
asyncResponse.resume(response);
return null;
}
});
}
}
But this way I need to manage my own thread executor and it feel's like I am missing something here.
Any suggestion on a different approach?
Here are a handful of recommendations, in order.
For context, I've been using Jersey for 2 years, and faced this exact problem 18 months ago.
1. Stop using #ManagedAsync
If you have control over the http server that Jersey is running on, I would recommend you stop using #ManagedAsync.
Instead of setting up Jersey to return it's http handling thread immediately and offload real request work to a managed executor service thread, use something like Grizzly for your http server, and configure it to have a larger worker thread pool. This accomplishes the same thing, but pushes the async responsibility down a layer, below Jersey.
You'll run into many pain points over the course of a year if you use #ManagedAsync for any medium-to-large project. Here are some of them off the top of my head:
If any ContainerRequestFilter's hits an external service (e.g. an auth filter hits your security module, which hits the database) you will lose the benefits you thought you were gaining
If your DB chokes and that auth filter call takes 5 seconds, Jersey hasn't offloaded work to the async thread yet, so your main thread needed to receive a new conn is blocked
If you set up logback's MDC in a filter, and you want that context throughout your request, you'll need to set up the MDC again on the managed async thread
Resource methods are cryptic to new comers and ugly to read because:
they need an extra parameter
they return void, hiding their real response type
they can "return" anywhere, without any actual return statements
Swagger or other API doc tools cannot automatically document async resource endpoints
Guice or other DI frameworks may have trouble dealing with certain scope bindings and/or providers in async resource endpoints
2. Use #Context and ContainerRequest properties
This would involve involved calling requestContext.setProperty("tenant_id", tenantId) in your filter, then calling calling requestContext.getProperty("tenant_id") in your resource with a #Context injected request.
3. Use HK2 AOP instead of Jersey filters
This would involve setting up an HK2 binding of InterceptionService which has a MethodInterceptor that checks for managed async resource methods and manually executes all RequestScoped bound ContainerRequestFilters. Instead of your filters being registered with Jersey, you'd register them with HK2, to be run by the method interceptor.
I can add more detail and code samples to options 2/3 if you'd like, or give additional suggestions, but it would first be helpful to see more of your filter code, and I again suggest option 1 if possible.

More than one user in the same Controller Spring MVC

I'm starting to develop for Web and I'm using Spring MVC as my Server Framework. Now I'm wondering about creating variables in Controller class. I had to do it to manage some data in server, but now I'm concerned about the following case: If I have more than one user sending information to the same page, at the same time, would one user interfere on another user variable?
Here's some code example:
#Controller
public Class myController {
int number;
#RequestMapping("/userInformation")
public String getInformation(int info) {
number = info;
}
public void doSomethingWithIt() {
number = number + 1;
}
}
In this case, If I have more than one user sending data to /userInformation at the same time, would Spring MVC create one Controller for each user? This way I wouldn't have problem, I guess. But if not, I have to rethink this implementation, don't I?
You are right. Controllers are singletons and must be stateless. Server side state belongs in session or in a data store. You can also use a request scoped object (look at bean scopes in spring).
The Spring container will create one instance of your Controller. So all users will share that instance.
If you have data that is private to a user, you have several options:
store it in the HTTP session (not recommended if it's a lot of data, as your memory usage might explode)
store it in a database and retrieve it upon each request, based on some property identifying the user
store it in a memory cache and retrieve it upon each request, based on some property identifying the user
Option 3 is the most simple one of them, you can even implement it as a Map<User, UserData> instance variable on your Controller if you like. It's not the cleanest, most beautiful or most secure option, just the most simple.
You should not use any instance variables in the Spring Controller that represent state of the controller class. It should not have state since its single instance. Instead you could have references to the injected managed beans.

Categories