What could be the reason why BeforeExecutingGetDataReader event unsubscribe does not work

I have another peculiar issue on my RO/DA server side which occurs very infrequent.

I have a RO service (SyncMasterService) with A DA service schema attached to it

I log all SQL calls by using the RO/DA events

I use a class SQLLogger of which an instance is member data of the Service object.

I hook the event in the constructor and I unhook the event in the dispose

This all works fine 99.9% of the time but at some point an event unsubscribe seems to fail.

From that point on the BeforeExecutingGetDataReader event is triggerd on a disposed object.

I assume this happens because the Service events are transferred to ServiceSchema events in the RO/DA code (and the serviceschema is shared between the service instances).

Is there a known issue (race condition?) with the events?

Any idea how I can prevent this?

Below some code fragments and at the bottom some loggings where we see that service instance creation #1062604 is the one where the event does not get unhooked. After that, it keeps triggering (Up to about 2 million instance creations).

image

First occurance: There is a lot of concurrence.

After that the event triggers on a disposed object

FYI: I am still on RO/DA for .NET v10.0.0.1611

Logged as bugs://D19711.

Ach, can this be resolved at your side, great

Meanwhile I have changed that service to a pooled service (seems more efficient and might reduce the issue. However I notice unexpected behaviour.

It looks like the initial number of services I create at startup are not kept in the pool.

What do you have to do to keep a pool of N always available?

… and after a while

Yes, that one is on our side .. a race in how we subscribe/unsubscribe your handler on the schema, which is shared between all service instances. Fix will be in the next release.

Here’s a workaround you can use right now, while we fix this on our side.

The race happens on the ServiceSchema object, which all your service instances share.
If each instance loads its own, it can’t happen.
Handle BeforeFindServiceSchema and hand DA your own schema then the shared one is never used

private readonly ServiceSchema schema_;

public SyncMasterService()
{
    schema_ = SchemaAccess.RetrieveSchema("SyncMasterService", typeof(SyncMasterService).Assembly);
    BeforeFindServiceSchema += (sender, e) => { e.ServiceSchema = schema_; };
}

What about the other issue (poolsize) Should I post this in a separate topic?

No I’ll reply shortly

Your pool setup is correct.

A pooled service is never disposed on release, it goes back into the pool.
So the Created + Destroyed on every call is not the pool that’s the StandardClassFactory pattern, and it matches your log exactly.

with PoolBehavior.CreateAdditional there is no upper limit, so N is the starting count, not a cap. Use PoolBehavior.Wait if you want exactly N.

On the event issue pooling won’t really change it either way, the sharing is on the schema rather than on the service instance.
The workaround I posted earlier should work correctly.

I think this is a different issue, I’ll post it in a separate topic