Race conditions with modelService.open(), suggestions?


#1

I have an async openModel(id) function whose contents include:

console.log('opening', id);
let model = await this._domain.models().open(id);
// check if another version of this model has already been opened.
// if so, close this one and use that one.
if (this._openedModels.hasOwnProperty(id)) {
  console.log(id, 'was already opened. closing');
  await model.close();
  model = this._openedModels[id];
} else {
  console.log('opened model', model.modelId());
}

In my app, this function gets called in parallel 4 times. I was assuming that in this case, 4 separate model instances would get returned, so I should close the three duplicates. But it seems as if calling close() closes every instance of this model. Is that accurate?

opening 2989d71003c5bb92
opening 2989d71003c5bb92
opening 2989d71003c5bb92
opening 2989d71003c5bb92
opened model 2989d71003c5bb92
2989d71003c5bb92 was already opened. closing
2989d71003c5bb92 was already opened. closing
2989d71003c5bb92 was already opened. closing

And the last two close() calls end up throwing exceptions: The model has already been closed: 2989d71003c5bb92


#2

OK, poking around the API docs I see a modelService.isOpening() method, which I will start using. Ideally, though, there would be a ModelOpened event or something I could listen to. Does something like that exist? I didn’t see anything here https://docs.convergence.io/js-api/interfaces/imodelevent.html


#3

Currently, a Model is only opened once per client. If you try to open the model again you will get a reference to the same model object. In terms of the event, the mode.open method returns a Promise as you already see, since you are using it. At the moment this is the only way to know when the model is open. If you do the following:

const modelService = domain.models();
const modelRef1 = modelServie.open("mymodel");
const modelRef2 = modelServie.open("mymodel");

const modelRef1.then((m) => "mode open for reference 1");
const modelRef2.then((m) => "mode open for reference 2");

The code would output:

mode open for reference 1
mode open for reference 2

The instance variable m that is resolved in both cases would be the identical object.

Furthermore if you did this:

const modelService = domain.models();
const modelRef1 = await modelServie.open("mymodel");
const modelRef2 = await modelServie.open("mymodel");

Then you are going to wait for the model to open, before calling open again. Since the model is already open, when you get to the second call to open, what is returned is a promise that is already resolved with the already open model.

So while we don’t have an event right now, you can check if a model is open, or opening, and if there is also no harm in just asking for it multiple times.

The only complexity in this right now, is if you are opening the model multiple times, it is not easy to know when to close() the model. We are looking at ways to deal with this, to make it easier.