0

I'm having trouble figuring out how to do an EJB3-compliant serial processing in a stateful bean. That is, have only one instance that can be accessed by a single thread only at a given moment. I can add synchronized to a method, but those are non-compliant additions, e.g.:

Reading this:

only one thread should be accessing it anyway, so puzzled.

I read this:

where it says:

An extension offered by JBoss EJB 3.0 is the notion of a @org.jboss.annotation.ejb.Service annotated bean. They are singleton beans and are not pooled, so only one instance of the bean exists in the server. They can have both @Remote and @Local interfaces so they can be accessed by java clients. When different clients look up the interfaces for @Service beans, all clients will work on the same instance of the bean on the server.

However, it does not say whether multiple threads can access it simultaneously. That is, if I have 10 clients which got a remote proxy to this @Service instance, they can call one method 10 times. Each of them will still operate on the same bean instance, but the method will be called multiple times. That's a testing result, I could not find anything specifically saying that in the API / docs.

This precludes this from being used in some scenarios such as e.g. producer / consumer ones where I need to process things in order and basically single threaded. Am I missing something? How to implement serial processing without resorting to other things (e.g. using DB locking or MDX or such)?

Btw, the code is simple / usual - here's the gist:

public interface MyService {
  public void callMe();
}

@Service
@Remote(MyService.class)
public class MyServiceImpl implements MyService {
  private Logger logger = Logger.getLogger(MyService.class);

  public void callMe() {
    logger.info("called entry");
    try {
      Thread.sleep(1000); // simulate work
    } catch(InterruptedException e) {
    }
    logger.info("called exit");
  }
}

Hope I did not make typos, but you get the idea. Cannot go to EJB 3.1 to try @Singleton, using ancient JBoss 4.2.1, no I cannot upgrade :(. When I run the above, I get several statements for entry, then they all wait a second, then they all exit. So if I were to process some state (and I read that @Service is a stateful bean), then all would get mangled up.

I thought of using @PoolClass(value=org.jboss.ejb3.StrictMaxPool.class, maxSize=1), but that would not help anything, as it's a single instance anyway, just accessed multiple times. Do you have any clues or directions?

And of course - adding synchronized to callMe method actually solves the issue, so not sure to think about all this. Server misconfiguration?

Community
  • 1
  • 1
levant pied
  • 3,886
  • 5
  • 37
  • 56
  • 1
    Seems like XY problem to me. What are you trying to process sequentially? – Jean Logeart Jan 02 '15 at 21:52
  • @JeanLogeart Fair enough. Think this - I have a legacy service that needs to be called each hour. It must be done exactly once for various reasons. It is done lazily when `callMe` method above is called. How to make sure a) I do it once b) I don't violate EJB3 "no-synchronized-touching" restriction? – levant pied Jan 02 '15 at 22:03
  • My answer, my bad, I was too quick to jump at the behavior your pointed. 1) From your sources, `Service` is the last thing you do; the "only one instance" points at it being reused by all threads. 2) Try with Session beans limiting the pool size to 1, https://developer.jboss.org/thread/34588?tstart=0 from your links it should work and 3) JMS is still an option worth considering. – SJuan76 Jan 02 '15 at 22:13
  • @SJuan76 "1) From your sources, Service is the last thing you do; the "only one instance" points at it being reused by all threads." Yes, but in EJB3 the container should make sure that a `@Stateful` (so also including `@Service`) bean instance is only touched by one thread at a time: http://www.adam-bien.com/roller/abien/entry/is_ejb_3_the_solution. Am I missing something? – levant pied Jan 05 '15 at 15:46
  • 2
    I don't think that I understand your question properly: are you trying to guarantee that only one instance of an EJB is available and it's also locked to a single caller at a time? IMO, your service objects should be stateless. State-preserving service objects (not SFSBs) are an antipattern to me – kolossus Jan 05 '15 at 18:21
  • @kolossus You understood correctly - one instance and single caller at a time. Also note that is only for one method that does the (re-)initialization. Agreed they should be stateless, however I'm wrapping another legacy library which has a costly initialization, so need a (single, shared) instance stored across calls. No other state except that, so if there are other / better ways to solve, I'm listening. – levant pied Jan 05 '15 at 22:36
  • Let me reconfirm: you want *only one instance* of a bean existing in the entire application @levantpied? – kolossus Jan 05 '15 at 23:58
  • The link you provide does not mention at any point that there is any relationship between JBoss `@Service` and EJB `@Stateful` (in fact it would quite the opposite, if `@Service` is singleton it should only hold shared state; otherwise it would not be reusable). – SJuan76 Jan 06 '15 at 09:39
  • @kolossus "you want only one instance of a bean existing in the entire application" Correct - I need to share an instance of the legacy library. Other solutions welcome, but at the end I think I need one of something (and I thought `@Service` bean would be the best choice given what it should guarantee) that holds one instance of the legacy library. – levant pied Jan 06 '15 at 14:40
  • @SJuan76 OK, got you, `@Stateful` is state per client call, `@Service` is shared across client calls. However, I still thought that `@Service` works in the same way as `@Stateful` and `@Stateless` in the sense that only one thread can be working on a particular instance (which is only one in case of `@Service`). Not sure how to approach my problem then - how to have a synchronized shared bean in JBoss? Is it that nobody else has these kinds of problems? :) – levant pied Jan 06 '15 at 14:49
  • Your scenario seems theoretically possible with CDI (not EJBs) but doesn't seem practical: Any kind of manual synchronisation around a single the EJB method will run the risk (result) of a deadlock at some point. There is an established pattern for the scenario you're facing : **Messaging**. You should have the clients submit requests to a queue and have your EJB process the queue sequentially. Attempting a synchronous, synchronised processing model cannot end well @levantpied – kolossus Jan 06 '15 at 17:01
  • 1
    I agree with @kolossus, read about JMS. You can create a `MessageDrivenBean` to process the requests. – SJuan76 Jan 06 '15 at 17:33

1 Answers1

1

How to implement serial processing without resorting to other things (e.g. using DB locking or MDX or such)?

You could use JMS with "Point-to-Point Messaging Style", although you cannot be sure the message was delivered to consumer (only to the queue).

Java EE 5 tutorial p2p JMS

jboss 4 JMS p2p example

  • Thanks JohnRambo. MDX is JMS - I wanted to avoid this. – levant pied Jan 13 '15 at 16:42
  • 1
    What you need is `@Singleton` with `@Lock(WRITE)` method, however it was introduced in EJB3.1. I think `synchronized` method or internal monitor/lock would be best solution. Also consider timeouts. –  Jan 14 '15 at 02:49