-
Notifications
You must be signed in to change notification settings - Fork 47
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
User payload for event handler subscription #17
Comments
I have to ask what priority of event handlers means. I see two possible interpretations:
I don't think that interpretation №1 has a sense for SObjectizer. Interpretation №2 can be archived by using |
I mean interpretation №2, of course. Yes, the splitting agent to group of agents and using prioritization at level of agents instead of level of event handlers is a possible solution. Unfortunately a changing some priorities during development becomes hard and produces a lot of work. Unnecessary entities make code more complicated. Also it may require additional synchronization depends on type of dispatcher. |
Ok, I took the point. I don't think that introduction of a custom field to some internal SObjectizer's structure is a good way to go. Because it isn't flexible enough, different users may want different types of that field. It seems that the main question is the reordering of messages stored in the agent's queue. And that reordering can (or should) be orthogonal to a dispatcher type. I need some time to think about it. |
That field may be pointer/union or type defined by dispatcher (not sure it's possible). |
It seems that I have some time to work on this issue. There is some idea of how a prioritized queue can be added to an agent without modification of existing dispatchers. But this idea has to be checked, maybe I'm wrong. Can you tell me some details about your implementation of the prioritized queue in your customized version of the SObjectizer? Do you use some custom dispatcher? |
Yes, i use custom dispatcher based on adv_thread_pool. Queue of demands is std::priority_queue. Priority of demand passing to execution_hint_t in same way as thread safety type. In methon push of dispatcher i use so_5::agent_t::so_create_execution_hint to get priority of demand from execution hint. |
Thanks, your answer adds a lot to think about... |
I think I would choose a different solution. I don't like the idea of extending subscription data by some additional info because it is impossible to predict which info will be required in different use cases. Sometimes it can be just For the prioritization of message handling I could imagine the following approach: using priority_type = ...; // Some application specific type.
class prioritizator {
protected:
~prioritizator() = default;
public:
prioritizator() = default;
[[nodiscard]]
virtual priority_type get_priority_for(
const so_5::execution_demand_t & demand) const = 0;
};
...
void some_ticky_dispatcher::push(so_5::execution_demand_t demand)
{
priority_type priority = lowest_priority;
auto * priority_getter = dynamic_cast<prioritizator*>(demand.m_receiver);
if(priority_getter) {
priority = priority_getter->get_priority_for(demand);
}
... // Storing of demand with detected priority.
}
...
class my_agent
: public so_5::agent_t
, protected prioritizator
{
protected:
[[nodiscard]] priority_type get_priority_for(
const so_5::execution_demand_t & demand) const override
{
if(demand.m_demand_handler == get_demand_handler_on_start_ptr())
return highest_priority; // so_evt_start should have the highest priority.
if(demand.m_demand_handler == get_demand_handler_on_finish_ptr())
return lowest_priority; // so_evt_finish should have the lowest priority.
if(std::type_index{typeid(some_message)} == demand.m_msg_type)
return ...;
if(std::type_index[typeid(another_message)} == demand.m_msg_type)
return ...;
...
}
}; You can have some reusable mixins like: class first_concrete_prioritizator : public prioritizator {
public:
[[nodiscard]] priority_type get_priority_for(
const so_5::execution_demand_t & demand) const override
{
...
}
};
class second_concrete_prioritizator : public prioritizator {
public:
[[nodiscard]] priority_type get_priority_for(
const so_5::execution_demand_t & demand) const override
{
...
}
}; and use them as mixins for specific agent types: class my_first_agent_type
: public so_5::agent_t
, protected first_concrete_prioritizator
{...};
class my_second_agent_type
: public so_5::agent_t
, protected second_concrete_prioritizator
{...}; |
Another way is to hold a mapper from a message type to a priority directly in a custom dispatcher. For example, if the priority depends on an agent, mbox, and message type there can be a map with keys in the form If the priority depends only on message type and the priority is known at the compile time a mapper can be implemented via variadic template class. |
The more I think about this topic the more ways I found without a need to modify SObjectizer's internals or SObjectizer's API. Another way is to use a pair of agent-collector and agent-performer. Agent-collector collects incoming messages and groups them by using various criteria (like message priorities). Agent-performer finishes the current task and asks the collector for a new one. The collector gets the next task from the internal queue and posts it to the performer the usual way. Anyway, I described the problem in my blog in Russian here. I posted a reference to that post on LinkedIn and Twitter but do not get any feedback. So I have no enough information to start the addition of such a feature to SObjectizer. And have to way for more time until there will be more demands for it :( Maybe with time, there will be more properly described real-world scenarios where the message priority handling is "the must-have" thing. But for now, I don't have such descriptions and can't check the applicability of various ways of extending SObjectizer. |
SObjectizer allows to prioritize agents, but often it's not enough. There are two another prioritization levels. First one is level of messages. Dispatcher can define specific class (derived from message_t) to inherit prioritized messages from and resolve message priority by this class. This is great, but may be too expensive sometimes. Another one is level of event handlers. It is powerful enough and cheap, also it is best solution for my case. Unfortunately there is no way to use that level at this moment. I had to patch SObjectizer to pass priority through
subscription_bind_t::event
and store it inexecution_hint_t
, but i wish SObjectizer had native way to do it.Optional argument of
subscription_bind_t::event
for user payload looks like suitable way that doesn't break backward compatibility. Also it may allow other possibilities for custom dispatchers.The text was updated successfully, but these errors were encountered: