list+org.o...@io7m.com a écrit le 07/08/2016 22:36 : > The more I think about this, the less it seems like a DS issue and more > like something more fundamental instead.
DS could help create write less code by exposing more functionality, but the general solution would remain the same. For instance, if activate() and deactivate() could return a Promise, we could have non-blocking components pretty easily, and let DS guarantee deactivate() is "done" before calling "activate" again. > Ignoring DS for now and assuming that only the direct OSGi service APIs > are being used: You have a service S in bundle B. S needs to do some > fairly long-running work on both startup and shutdown before it can be > used. Bundle B can be restarted at any time, so the startup and shutdown > code in S must be protected against multiple instances of S executing > concurrently. I must admit that I'm not yet familiar with the core > OSGi service APIs, but I assume that they have similar constraints to > DS in that you're not supposed to block the runtime when it makes calls > into your code. Yes, a bundle activator should avoid blocking too long during its start/stop callbacks. However, there's no necessarily a need to protect for concurrency just because it's asynchronous and long-running. You need to protect when the long-running code has side-effects that you explicitly guard against. That is the case with your socket binding, because you want to reuse a specific system resource. And because, in that case, the only way to know you have cleared that resource is binding *after* the call to close. > The workaround to this workaround is to store something statically, > such as a Thread or an ExecutorService that is shared between all > instances of T. This seems nightmarish to me though, in a system with > as much dynamism as OSGi. Another option is to place S and T in > separate bundles so that S can be restarted independently of T and > therefore T is not recreated and can continue keeping things serial. > This seems pretty nasty though... Creating entire new bundles just to > work around a concurrency issue. The workaround is useful when you have any long initialization. We have some that takes 30sec. In your case, with a socket, I would just do it in activate and deactivate, because it's quick enough. Your call to close, that sets a flag, would return a Promise. The promise would be resolved when your thread dies. I would block on the promise in the deactivate method. > Every single server application I've written in the past eight years or > so has involved moderately lengthy initialization and shutdown work. I > feel like I'll be running into this issue again and again. I'm quite > disturbed that I've run into something like this in the very first > "could not be simpler" OSGi program I've written. > > Am I missing something here? First, most people will choose to block if it's a short operation. If it's not, there's the work around I mentioned. But mostly, when you try to use OSGi to handle the dynamism completely (which many applications built on top of OSGi ignore), you see that initialization and shutdown becomes trickier. On the one hand, things are easier because when you initialize things, you can make services out of them and link their registration lifecycle to their "validity" lifecycle to some extent. They're easy to consume, and components build on top react nicely to state changes out of the box. On the other hand, a few problems that were silent in a monolithic or static setting become apparent. -- Simon _______________________________________________ OSGi Developer Mail List osgi-dev@mail.osgi.org https://mail.osgi.org/mailman/listinfo/osgi-dev