exactor icon indicating copy to clipboard operation
exactor copied to clipboard

Possibility of custom process registration dispatching logic?

Open Qqwy opened this issue 7 years ago • 7 comments

Right now, it is possible to either return a PID, or to register using :global or :via. However, this needs to be given as option when ExActor.GenServer is included (used).

This unfortunately which means that it is impossible to build custom logic, to e.g. register at {:via, Registry, {MyRegistry, "user_#{user_id}"}}.

Maybe, a possibility would be to allow users to write a custom export function, which is used for the different functions to transform the first argument into a term like above that could be used to do the actual GenServer dispatching on.

Qqwy avatar May 31 '17 20:05 Qqwy

It is possible to use via tuple by using private macros (defstartp, defcastp, ...), but this requires additional wrapping, and pretty much makes ExActor as noisy as GenServer. I discussed this in #26.

Your proposal is very interesting, and at first glance I like it. We could support a callback function (e.g. server_pid/1), which would by default be an identity function. It could be overridable, so in the implementation you can override the behaviour and turn it into e.g. a via tuple. The function should be invoked only if export option is not provided.

Would you be willing to make a PR? The code is somewhat convoluted, what with all the macro logic, so if you don't feel like it, I could give it a stab.

sasa1977 avatar Jun 01 '17 09:06 sasa1977

Yes, I am willing to give the creation of a PR a go :-).

Qqwy avatar Jun 01 '17 10:06 Qqwy

Good luck :-) If you get stuck somewhere, feel free to ask.

sasa1977 avatar Jun 01 '17 10:06 sasa1977

I think the cleanest way would be to just define server_pid as a normal function that can be overridden (by ExActor specifying defoverridable [server_pid: 1]) by the user. Do you agree?

Qqwy avatar Jun 01 '17 12:06 Qqwy

Yeah, that's what I thought as well.

sasa1977 avatar Jun 01 '17 12:06 sasa1977

All right.

I worked a little bit on this today, as I finally had some spare time.

However, I'm still unable to find the proper location to add the new logic.

I am guessing it is close to Exactor.Operations.server_ref/2, but I am unsure what server refers to in the quote(do: server) statements. (Is this a snippet that is inserted somewhere else in an unhygienic way?)

Qqwy avatar Jun 10 '17 16:06 Qqwy

I pushed a small refactoring commit into a separate branch. With that change, the definition of the interface function for calls/casts is now done in the single place.

Roughly speaking, you need to do the following. If type is neither :multicall nor :abcast, and :export option is nil or false, you need to do something along the lines of:

  1. Split gen_server_args into head/tail (outside of the quoted block).
  2. Inside the quoted block invoke the new callback with injected head from step 1.
  3. Modify the invocation in line 587 and pass the result from step 2 followed by unquote_splicing(tail_from_step_1).

If type is :multicall or :abcast, or :export option is neither nil nor false, you should use the same quoted code as in line 587. So you'll add an if before line 586, and then either return the verbatim copy of the existing quote block, or a more elaborate quote block as described above.

I didn't try this out, so I might have missed some possible problems or fine-print details :-)

You can cherry pick my commit into your branch, and then try to see if my proposal takes off.

sasa1977 avatar Jun 10 '17 17:06 sasa1977