-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to change the order of subscribers? #257
Comments
Wesley Barroso Lopes wrote at 2022-3-28 11:57 -0700:
...
In a Plone addon, I registered a subscriber:
```xml
<subscriber for="my.products.contents.mycontent.IMyContent
OFS.interfaces.IObjectWillBeRemovedEvent"
handler=".handler.myhandler" />
```
### What I expect to happen:
I would like this event of mine to be executed before the subscribers registered by Zope.
Subscribers are a special kind of subscriptions.
The documentation specifies the order in which subscriptions are returned.
It is influenced by the registration order.
Thus, controling the registration order allows you to influence
the subscription order. The `site.zcml` determines the top level
registrations, each of its directives can recursively cause
further registrations. Thus, it is possible (though quite difficult)
to ensure that your registrations are the first or last ones
(I do not know what is necessary to achieve your goal -- read the
documentation or try it out).
The other possibility is to directly change
`zope.event`'s `subscribers` data structure.
The event mechanism is implented by (--> `zope.event:__init__`):
```
subscribers = []
def notify(event):
""" Notify all subscribers of ``event``.
"""
for subscriber in subscribers:
subscriber(event)
```
`Zope` puts a function `dispatch` into `subscribers[0]` which
delegates the event processing to the subscription registries
of `zope.component/zope.interface`.
You can put your own "subscriber" in `zope.event.subscribers` before
the default event processor (i.e. the `dispatch` above).
This will guarantee that its effects come before the standard ones.
Unfortunately, subscriptions (unlike `adapters` and 'utilities`)
cannot be named. It is therefore not easy to use the
`zope.component/zope.interface` registries for your own
subscriber function. You might need to create your own registries
for this purpose: they can work like the standard registries
but have their own content.
You could also replace `dispatch`.
Your replacement might for example determine the sequence
of all applicable subscriptions and then decide about the order
in which they should get applied.
Neither approach is easy:
`zope.event/zope.interface` simply lacks support to easily
control the order in which event handlers are executed.
|
I just couldn't in any way put my subscriber ahead of Zope's. This would be a great feature for Zope. What I'm trying to do is prevent the deletion of content, under certain conditions. So I thought I'd make a subscriber that checks this and raise an exception in case the object can't be deleted. It's just that there are subscribers that run before mine, that do things to the object, like uncatalog from catalog. |
Wesley Barroso Lopes wrote at 2022-3-29 12:26 -0700:
What I'm trying to do is prevent the deletion of content, under certain conditions.
For this use case, it is not necessary that your subscriber runs
before the normal subscribers: your subscriber will be informed
about the deletion -- and if it objects, it can raise
an exception. Then the transaction will be aborted and the deletion
will not take effect.
It will not work for a Zope `Manager`: someone decided that
exceptions during a deletion by a `Manager` should not prevent
the deletion. But, non `Manager` deletions can be prevented in this
way.
You can use a specific exception and register a corresponding
error view: to inform the user about the prevented deletion.
Without such an error view, the user will see a standard error message.
|
If I catch the exception to display a friendly message, there is no rollback of things done by subscribers, like uncatalog. |
Wesley Barroso Lopes wrote at 2022-3-29 15:17 -0700:
> You can use a specific exception and register a corresponding
> error view: to inform the user about the prevented deletion.
If I catch the exception to display a friendly message, there is no rollback of things done by subscribers, like uncatalog.
You do not catch the exception: an error/exception view does
not change transaction handling -- even if it "fires" the transaction
is aborted.
|
@d-maurer remembering that I'm in the Plone context. In Plone, I can delete multiple objects at the same time. So it is necessary to catch the error, because some objects can be deleted and others not, in the same request. See:
|
Wesley Barroso Lopes wrote at 2022-3-30 05:11 -0700:
***@***.*** remembering that I'm in the Plone context. In Plone, I can delete multiple objects at the same time. So it is necessary to catch the error, because some objects can be deleted and others not, in the same request. See:
Then, I am in doubt that your design it right.
Apparently, you want to prevent (under the hood) the deletion of some objects
while in the same transaction you want to delete other objects.
Deletion has a semantics: if it succeeds, the deleted object
should no longer be there. If it fails, the transaction should
get aborted -- to keep a consistent persistent state.
Do not call Zope/Plone's deletion methods when you do not
want this semantics.
You can use `transaction.savepoint` to emulate nested
transactions. This would allow you to catch exceptions
from parts of your request processing and manually roll back
the persistent changes from those parts.
Still, you could not perform deletion of some objects
and prevent deletion for other objects in those parts
but other parts could do whatever they want (including
deletion of objects not prevented by your special logic).
|
Yes, that's why it would be good for validation to be on the subscriber. But for this to work, my subscriber would have to be run before Zope's subscribers. That's why it would be interesting to be able to choose the order of execution of the subscribers. I think I'll open an issue on zope.configuration requesting this feature |
BUG/PROBLEM REPORT (OR OTHER COMMON ISSUE)
What I did:
In a Plone addon, I registered a subscriber:
What I expect to happen:
I would like this event of mine to be executed before the subscribers registered by Zope. When I delete an object of mine, the notification occurs:
In that notification, the event:
runs before mine. How do I get mine to run sooner?
What actually happened:
Event registered by Zope runs before mine.
What version of Python and Zope/Addons I am using:
Python: 3.8.12
Zope 4.6.3
zope.interface 5.4.0
The text was updated successfully, but these errors were encountered: