On Fri, 7 Oct 2022 at 07:49, Jiri Daněk <[email protected]> wrote:
>
> On Thu, Oct 6, 2022, 19:07 Timothy Bish <[email protected]> wrote:
>
> > On 10/6/22 12:19, Jiri Daněk wrote:
> > > On Thu, Oct 6, 2022 at 5:19 PM Timothy Bish <[email protected]> wrote:
> >
>
> [...]
>
> > Sounds like the right strategy for me (at least, to solve my immediate
> > > problem) is
> > >
> > >              Tracker tracker = sender.send(message);
> > >              tracker.awaitSettlement();
> > >              while (tracker.remoteState() != DeliveryState.accepted()) {
> > >                  // TODO: am I supposed to increment `delivery-count` of
> > the
> > > message if I got rejected before?
> > >                  //  as per
> > >
> > http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#type-rejected
> > >                  tracker = sender.send(message);  // resend the message
> > >                  tracker.awaitSettlement();
> > >              }
> >
>
> (NB. This is not a busy loop involving the network, because sooner or later
> the peer will drain my credit, if it intends to keep blocking me. And
> sender.send() blocks upon running out of credit, as was already said
> before.)
>
> Anyways, the above forces me to have only one message in flight even though
> applications can usually benefit from having multiple messages in flight.
>

You are in no way 'forced' to have a single message in flight if you
dont want to. Just like the proton 'container' based clients that
behave much the same in all these regards (and is in part behaviour
that the imperative API was based on, expecting to be built on top of
it for some of the other clients) modulo their reactive vs imperative
API styles.

The above code is effectively a synchronous send with retry
implementation that you have created. By doing that you have expressly
chosen to use the underlying async send constructs to build something
to send stuff synchronously in that way. If you dont actually want to
do that because you have other messages to send in flight, then...do
something else.

> Seems like it should work for your test case, other options are to delay
> > resend (possibly with back off) or resend up to some max limit,
>
>
> I don't see much point in those sophisticated strategies with delays, etc
> for resends (as opposed to reconnect). When the remote peer stops accepting
> messages, it should be either because there is something wrong with the
> messages (and then there is no point in resending the same thing again) or
> because the peer is unable to handle any messages right now, and then it
> should drain my credit. Plain send attempt (which blocks on having credit)
> should then be the most appropriate answer.

If you have explicitly configured your peer to refuse messages due to
a resource constraint, then you ultimately have to accept that it
might actually do so. It attempting to drain credit doesnt preclude
you having already used the credit you got for sends still in flight,
and so still hitting such refusals.

Of course, I believe the peer in question also has a configurable way
to continue to accept such messages caught in the already-in-flight
race, up to a limit, before actually refusing them, since I nagged for
that to implemented precisely to help minimise the cases such refusals
would need to be occur.

>
> (Peer can't simply drain credit for anonymous producers, I guess, so ok,
> maybe there is a point in these client-driven retry strategies sometimes.)
>
>
> > all of
> > which will depend on your application and how you decide to handle send
> > errors.
>
>
> One could make the same argument against providing reconnect and reconnect
> strategies (exponential delay, maybe with jitter) in an AMQP library.
>
>
> > > Is there an example? Looking at
> > >
> > https://github.com/apache/qpid-protonj2/blob/f215929395e44a8a0679befe15f96fd95b634c16/protonj2-client-examples/src/main/java/org/apache/qpid/protonj2/client/examples/Send.java#L47
> > ,
> > > that waits for the settlement, but it does not check what it is. So, if
> > the
> > > peer rejects the message, the Send example finishes without reporting any
> > > errors. AFAIK none of the examples does actually check the
> > > tracker/disposition. One-way ack sounds to be the default that most users
> > > will want.
> >
> > We chose to keep the included samples small and concise as a "production
> > ready" example tends to not be production ready based on how your own
> > application chooses to respond to errors etc and the samples quickly
> > become to complex for a novice user to get started.
> >
>
> > To be honest, I am not entirely clear what are the reasonable responses to
> > > getting rejected, modified, or released dispositions. So a more
> > > production-ready =copypastable example of "I just want to send a message"
> > > would be very welcome!
> >
> > The specification defines the meaning of each state
> >
> >
> > http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#section-delivery-state
> >
> > You application then needs to decide how to best handle / report those
> > outcomes.
> >
>
> How does a typical messaging user learn what possible dispositions might
> their broker (let's use Artemis as an example) issue, and how these map to
> different broker features? Looking at that AMQP spec in isolation, I
> certainly would not realize there is logic needed to handle full addresses.
> Do I really need to read the broker docs from cover to cover? (
> https://activemq.apache.org/components/artemis/documentation/latest/flow-control.html,
> section Blocking AMQP Producers; moreover, the docs say "Once this upper
> bound is reach Artemis will start rejecting AMQP messages." It does not
> make any explicit reference to AMQP dispositions, so it can be easily
> missed when searching for it).
>
> In the AMQP world, it is even possible to write portable clients, or are
> the differences and gotchas between different peers (Artemis, Dispatch
> Router (which does not always grant credits to receivers by default...), or
> Azure Service Bus) so great that it is necessary to focus on one, and then
> there is extensive testing required to catch all those quirks? And every
> user of the peer has to discover them for themselves, when building a
> client?



>
> On Thu, Oct 6, 2022 at 8:43 PM Connie Yau <[email protected]>
> wrote:
>
> > Hey,
> >
> > You can take a look at the Tracker object returned from a send operation
> > to understand the state of that message. For example, you could use
> > `Future<Tracker> settlementFuture()`
> > https://github.com/apache/qpid-protonj2/blob/main/protonj2-client/src/main/java/org/apache/qpid/protonj2/client/Tracker.java#L93
> >  and
> > await it then examine the remoteState() for that returned Tracker.
> >
> > I hope this helps,
> > Connie
> >
>
> Thanks, yes, that is a start.

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to