I would view resource destructors as the last ditch effort to cleanup. In other words, when you are done with the operation your erlang code should call a nif function (e.g, done/1) to clean up immediately. In your resource destructor you should check to see if said cleanup was already performed, if not, then destroy.
You can count on resource dtors to run, the question of course is when, and this will be dependent on the behavior and/or life cycle of the process (i.e., when a gc happens iirc).
Is that infeasible for your case for some reason?
Edit :
Note : I should have noted, my statement is tangential to your question. Yet, I could not help but infer a few things from your statements and questions. I do think someone from OTP team needs to answer your question.
I did try to trace the code a bit myself. This code hasn’t changed in later versions of erts, so it’s not just OTP 22. I don’t believe it will always run on the first scheduler, it does try to grab the current scheduler, but clearly that won’t always happen, as there is a fallback to scheduler 1.
Of course, I myself am curious whether it could be specified on nif initialization that you want to run a resource dtor on a dirty scheduler vs a normal scheduler.
I also wonder if it’s possible to yield from a dtor, but it doesn’t look like it at a glance, even if you’re running on a dirty scheduler it would not be great to block for a terribly long time. However, in some cases all bets may be off if you’re resource is actually managed by an foreign library.
While waiting on someone from OTP team to respond, do you mind telling us about the length of time on average you spend tearing down a resource and what type of resource?