Open k7sleeper opened 9 years ago
This is due to the caching mechanism implemented in Container.assemble()
. If we want your use case to be supported we should invalidate and rebuild that cache when adding new particles.
One question, is any particular reason you need to support "hot" registration of new particles? Consider that this may have repercussions on other features like module overriding, what happens if a module is overridden by the new particle but it was already loaded from another module? This goes beyond what we currently can do in Node.
My reason is, that modules under components.1
may have a dep to a module which is created and registered at scatter after calling service init
. In other words, components.0
provides service init
which creates an object which is registered at scatter and is a dep of modules in components.1
.
Why it works with the first code snippet is the fact, that scatter loads deps not before the module which needs the dep is loaded.
The first code snippet fails, when calling (for what reason ever) scatter.initializeAll()
!
Let's analyse one problem at a time. The second snippet is not working because the invocation of a service will cause the initialisation and loading of all the modules in its namespace, which in your case is the root. The modules and namespaces are cached for performance reason, so when you add another particle the new modules are simply not picked up, because the cache is used instead.
Now, your use case creates even a bigger problem, because if all the modules are already wired together (after the first service is invoked), adding a new particle with new modules could potentially mean that all the modules have to be re-linked, and this is a task close to impossible without restarting the entire application.
My advice is to try to simplify your solution, for example, trying to dynamically register a module which in turn provides a service, looks to me like a task that Scatter itself should be doing...
I did not get your advice.
Now, my idea is to work with 2 Scatter instances, one for initializing the app, the 2nd for starting and running the app. The first is thrown away after initialization is done, the 2nd is created after initialization because at this moment all deps for running the app are available.
Could that be an approach?
Having 2 different scatter instances would work only if you defined all your modules as factories and constructors, because in that case all modules would be re-created and re-initialized. object
modules are cached by Node.js and will be shared between the 2 Scatter instances, with unpredictable results.
Could you please tell me more about what happens in the initialisation phase?
In the initialisation phase more or less the app config is read from a JSON file, a JSON schema validation is done and a appConfig object is created and prepared for the other modules.
Does the config affect what modules are loaded? Or it's just a set of parameters?
It's just a set of parameters.
But during initialization, you are actually inserting new modules in Scatter right? and you also want to insert particles (during the init), is that correct?
Yes, during initialization this app config object is registered (when it is completely prepared) at Scatter.
After initialization, the core particles are inserted in Scatter.
Why don't you initialize the config before instantiating Scatter? This is actually a pattern I used for Hadron and Particles. The config object is really a prerequisite for Scatter, especially if you use it to load other particles. Is that a feasible alternative for your project?
That's what I did in previous projects. I'm not entirely satisfied with that approach!
Reading the config and preparing it requires some modules (General info, JSON Schema validators, some assets, ...) which I also need later in the particles. These modules have some dependencies which, I thought, could be useful to wire together by Scatter.
So, I thought that it could be a good approach to use Scatter as soon as I have a logger object for Scatter. My app start sequence in my lastest project is now:
Currently, my work around is, registering all particles together with the 'start-up' particle, hoping that Scatter only loads a module when it's needed. It works for me as long as I don't call scatter.initializeAll()
which I luckily don't need.
Looking at your use case, a possible solution would be to scope your first service to specific namespace, for example:
'svc|sequence!initializers/init'
'svc|sequence!start'
This would cause only the initializers
namespace to be initialized and cached. Give it a try and let me know.
It works!
Thanks for this hint!
Perfect! Glad it worked! :fireworks:
This works
but registering the second particle later
does not work (service
init
is provioded byparticle.0
, servicestart
is provioded byparticle.1
).