Skip to content

Support :mbox-type for pinned dispatchers#111

Merged
mdbergmann merged 3 commits intomdbergmann:masterfrom
svetlyak40wt:mbox-type-for-pinned
Jan 2, 2026
Merged

Support :mbox-type for pinned dispatchers#111
mdbergmann merged 3 commits intomdbergmann:masterfrom
svetlyak40wt:mbox-type-for-pinned

Conversation

@svetlyak40wt
Copy link
Contributor

@svetlyak40wt svetlyak40wt commented Jan 1, 2026

Also I've added an ability to pass a function instead of class-name. This is useful, when you want to create an message box instance with arguments other than supported by base implementation.

Usage example:

(defclass deduplication-message-box (sento.messageb:message-box/bt)
  ((deduplicatep :initarg :deduplicatep
                 :type function
                 :reader message-box-deduplicate-p)))


(defgeneric search-in-queue (queue predicate)
  (:method ((queue queue-bounded) predicate)
    (error "Search in cl-speedy-queue:queue is not supported yet."))

  (:method ((queue queue-unbounded) predicate)
    (let ((inner-queue (slot-value queue 'sento.queue::queue))
          (lock (slot-value queue 'sento.queue::lock)))
      (check-type inner-queue sento.queue::queue)

      (bt2:with-lock-held (lock)
        (let ((head (sento.queue::queue-head inner-queue))
              (tail (sento.queue::queue-tail inner-queue)))

          (or (find-if predicate tail
                       :key #'sento.messageb::message-item/bt-message)
              (find-if predicate (reverse head)
                       :key #'sento.messageb::message-item/bt-message)))))))

(defmethod submit :around ((self deduplication-message-box) message withreply-p time-out handler-fun-args)
  (cond
    (withreply-p
     ;; We can't deduplicate messages for which caller is waiting for the reply:
     (call-next-method))
    ((null (search-in-queue (slot-value self 'sento.messageb::queue)
                            (alexandria:curry (message-box-deduplicate-p self)
                                              message)))
     (call-next-method))
    (t
     (log:warn "Message was deduplicated" message))))
     
     
;;; Then, when creating an actor:

(defun deduplicate-message-with-site-config (message-to-check message-from-queue)
  "Returns T if message-to-check is equal to message-from-queue"
  (and (listp message-to-check)
       (listp message-from-queue)
       (eql (first message-to-check)
            (first message-from-queue))
       (equal (bot/config::chat-id (second message-to-check))
              (bot/config::chat-id (second message-from-queue)))))


(defun create-mbox-with-site-actions-deduplication (&key (max-queue-size nil) &allow-other-keys)
  (when max-queue-size
    (error "Deduplication queue does not work with bounded queues yet."))

  (make-instance 'deduplication-message-box
                 :deduplicatep #'deduplicate-message-with-site-config))


(defun create-site-updater (actors-system)
  (sento.actor-context:actor-of actors-system
                                :receive #'do-update
                                :dispatcher :pinned
                                :name "site-updater"
                                :mbox-type #'create-mbox-with-site-actions-deduplication))

Also I've added an ability to pass a function instead of class-name. This is useful,
when you want to create an message box instance with arguments other than supported
by base implementation.
@mdbergmann
Copy link
Owner

This is cool.
Can you please add a test case similar to actor-of--custom-dispatcher-with-custom-mbox-type in actor-context-test.lisp showing that the wiring works as it should.

(:pinned
(etypecase eff-mbox-type
(function
(funcall eff-mbox-type :max-queue-size queue-size))
Copy link
Owner

Choose a reason for hiding this comment

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

I think it would be good to check if the generated instance is at least message-box-base.

Copy link
Owner

@mdbergmann mdbergmann left a comment

Choose a reason for hiding this comment

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

OK, looks look. Thanks.

@mdbergmann
Copy link
Owner

That's a good point:

;; We can't deduplicate messages for which caller is waiting for the reply

Actually, withreply-p is just used for the synchronous reply.
Any async reply, should there be multiple requests, will probably also leave one requester waiting.
But that's up to the user of custom mailbox.

@svetlyak40wt
Copy link
Contributor Author

I don't understand whether something else needs to be changed in this regard, or if everything is already fine as is?

@mdbergmann
Copy link
Owner

I don't understand whether something else needs to be changed in this regard, or if everything is already fine as is?

It's fine.
I'll merge...

@mdbergmann mdbergmann merged commit d522b49 into mdbergmann:master Jan 2, 2026
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