Skip to content
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

Add a way to pass additional arguments to an actor constructor #91

Merged
merged 7 commits into from
Jul 1, 2024

Conversation

svetlyak40wt
Copy link
Contributor

@svetlyak40wt svetlyak40wt commented Jun 28, 2024

I've removed :other-args argument.
Probably it should be returned back for backward compatibility?

I've removed :other-args argument.
Probably it should be returned back for backward compatibility?
@@ -18,7 +18,8 @@
(in-package :sento.actor-context)

(defgeneric actor-of (context
&key receive init destroy dispatcher state type name other-args)
&key receive init destroy dispatcher state type name queue-size
Copy link
Owner

@mdbergmann mdbergmann Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be OK for you to not have the queue-size here and instead process it as part of rest? Because I think that to 95% of the use cases the default unbounded queue is being used. It can still be documented as docstring what additional parameters are being accepted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will work, but I think it is much more convenient to have known arguments listed explicitly, because IDE will suggest their names.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true. But I don't want users to be confused what to choose here and whether it is relevant on constructing an actor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've removed queue-size from explicit arguments of generic function, but leave this keyarg for a method where it is used.

"See `ac:actor-of`."
(check-type receive function "a function!")
(alexandria:remove-from-plistf rest
Copy link
Owner

@mdbergmann mdbergmann Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? IMO it doesn't look great and adds an additional burden to strip keys here (and in the other places.
What happens if the keys are not removed?

Copy link
Contributor Author

@svetlyak40wt svetlyak40wt Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these keys are not removed from the REST, they will be passed along to the act:make-actor and will cause error like:

Invalid initialization argument:
  :DISPATCHER"


 0: (SB-PCL::INITARG-ERROR #<STANDARD-CLASS SENTO.DISPATCHER:DISPATCH-WORKER> (:DISPATCHER))
 1: ((:METHOD MAKE-INSTANCE (CLASS)) #<STANDARD-CLASS SENTO.DISPATCHER:DISPATCH-WORKER> :RECEIVE #<FUNCTION SENTO.DISPATCHER::RECEIVE> :INIT N$
 2: ((:METHOD MAKE-ACTOR (T)) #<FUNCTION SENTO.DISPATCHER::RECEIVE> :INIT NIL :DESTROY NIL :STATE NIL :NAME "dispatch(SHARED)-worker-1" :RECEI$
      Locals:
        #:.DEFAULTING-TEMP. = SENTO.DISPATCHER:DISPATCH-WORKER
        SENTO.ACTOR::ALL-ARGS = (:INIT NIL :DESTROY NIL :STATE NIL :NAME "dispatch(SHARED)-worker-1" :RECEIVE #<FUNCTION SENTO.DISPATCHER::REC$
        SENTO.ACTOR::RECEIVE = #<FUNCTION SENTO.DISPATCHER::RECEIVE>
        TYPE = SENTO.DISPATCHER:DISPATCH-WORKER
 3: ((SB-PCL::EMF MAKE-ACTOR) #<unused argument> #<unused argument> #<FUNCTION SENTO.DISPATCHER::RECEIVE> :INIT NIL :DESTROY NIL :STATE NIL :T$
 4: ((LAMBDA NIL :IN SENTO.ACTOR-CONTEXT:ACTOR-OF))
 5: (SENTO.ACTOR-CONTEXT::%CREATE-ACTOR #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}> #<FUNCTION (LAMBDA NIL :IN SENTO.ACTOR-CONTEXT:ACTOR$
      Locals:
        CONTEXT = #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}>
        CREATE-FUN = #<FUNCTION (LAMBDA () :IN SENTO.ACTOR-CONTEXT:ACTOR-OF) {10061575BB}>
        DISPATCHER-ID = :PINNED
        QUEUE-SIZE = NIL
 6: (SENTO.ACTOR-CONTEXT::%ACTOR-OF #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}> #<FUNCTION (LAMBDA NIL :IN SENTO.ACTOR-CONTEXT:ACTOR-OF)$
 7: ((:METHOD SENTO.ACTOR-CONTEXT:ACTOR-OF (SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT)) #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}> :RECEIVE #<F$
 8: ((SB-PCL::EMF SENTO.ACTOR-CONTEXT:ACTOR-OF) #<unused argument> #<unused argument> #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}> :RECEI$
 9: (SENTO.DISPATCHER:MAKE-DISPATCHER-WORKER 1 #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}> :SHARED)
10: ((:METHOD INITIALIZE-INSTANCE :AFTER (SENTO.DISPATCHER:SHARED-DISPATCHER)) #<SENTO.DISPATCHER:SHARED-DISPATCHER ident: SHARED, workers: 0,$
11: ((LAMBDA (SB-PCL::|.P0.| SB-PCL::|.P1.| SB-PCL::|.P2.| SB-PCL::|.P3.|)) #<unavailable argument> #<unavailable argument> #<unavailable argu$
12: (SENTO.DISPATCHER:MAKE-DISPATCHER #<SENTO.ACTOR-CONTEXT:ACTOR-CONTEXT {1006010683}> :SHARED :WORKERS 4 :STRATEGY :RANDOM)
13: (SENTO.ACTOR-SYSTEM::%REGISTER-DISPATCHERS #<SENTO.ACTOR-SYSTEM:ACTOR-SYSTEM config: (SCHEDULER (ENABLED TRUE RESOLUTION 100 MAX-SIZE 500)$
14: (SENTO.ACTOR-SYSTEM:MAKE-ACTOR-SYSTEM (:DISPATCHERS (:SHARED (:WORKERS 4 :STRATEGY :RANDOM))))
15: ((LABELS %TEST-COUNTER-MP-UNBOUNDED :IN "/home/art/.cache/common-lisp/sbcl-2.4.4-linux-x64/home/art/projects/cl-gserver/tests/actor-mp-tes$
16: ((LABELS IT.BESE.FIVEAM::RUN-IT :IN IT.BESE.FIVEAM::RUN-TEST-LAMBDA))

This error is generated because actor class does not have :DISPATCHER initarg.

I've found that in this case we can replace lengthy:

(alexandria:remove-from-plistf rest
                                 :queue-size
                                 :dispatcher
                                 :init
                                 :destroy
                                 :state
                                 :type
                                 :name)

With only:

(alexandria:remove-from-plistf rest
                                 :queue-size
                                 :dispatcher)

or we can remove alexandria:remove-from-plistf completely but pass :allow-other-keys t to the make-instance. But this way we will turn off check of keyword argument and library user might be surprised when hi mistype an argument name and actor's slot will not be filled with the value.

I'd go with a smaller number of excluded argument names but not turn off names checking.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

(sento.queue:queue-full-error ()
(incf queue-full-counter))))

(sleep 2)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better use await-cond or some such here because we may have the result earlier and can spare some test runtime.
Possibly the 1 sec wait in receive can also be reduced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refactored code like this, but it required some changes in complete-p function.

Could you please review if it is ok to change complete-p this way? If so, probably a separate test should added for the cases where future can become completed with error.

What is interesting, I've replaced TELL with ASK and ASK does not raise sento.queue:queue-full-error error as TELL does. Instead it returns a "errored" future. Is this desired behaviour?

Copy link
Owner

@mdbergmann mdbergmann Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ask always returns future. Insofar it consistently also delivers any errors as future result. While it's consistent it has a technical reason: ask spawns an anonymous actor that does the tell (and also waits for response via reply) so that the call to ask can be async.

@mdbergmann
Copy link
Owner

I've removed :other-args argument. Probably it should be returned back for backward compatibility?

I don't know if this is used by many, if any at all. But we don't know and it may be we break it for some.
I'm using it in other projects and I'll probably have to adapt.
I think we can just make the change and see if someone complains.

@@ -96,7 +97,21 @@ Create a future with:
(defun complete-p (future)
"Is `future` completed? Returns either `t` or `nil`."
(with-slots (promise) future
(promise-finished-p promise)))
(or (promise-finished-p promise)
;; QUESTION:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's OK. error result can be considered completed.

Copy link
Owner

@mdbergmann mdbergmann Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test-case for the changes, and for error-p.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added complete-with-error test.

@mdbergmann
Copy link
Owner

If you don't have more I'd merge.

@svetlyak40wt
Copy link
Contributor Author

If you don't have more I'd merge.

Yes, I'm done.

@mdbergmann mdbergmann merged commit 1c7eaa0 into mdbergmann:master Jul 1, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants