-
Notifications
You must be signed in to change notification settings - Fork 476
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
ConfirmChannel#publish / ConfirmChannel#sendToQueue should return a promise ? #89
Comments
I assume it returns true or false to indicate whether all confirms were received successfully. |
Indeed it does , but would be awesome to have it consistent with other promise-like interfaces .. e.g.
|
@pdelanauze channels that don't use publisher confirms don't have a "success" value to return (publishing is then fire-and-forget). Channels that do use publisher confirms need to return a value. Other clients use a separate method for this, though, but it is uncommon to return a 2-tuple in JavaScript libraries. |
I'm not sure if the |
Yep, got it . |
|
I don't like the
On the other hand, I could probably do a bit better than callbacks in amqplib's confirm channels, at least by providing extra bits of library. |
Would be interesting to have promises around ConfirmChannels, it's how we expected it to work , but the callbacks are definitely fine for now |
OK, good to know. One difficulty with returning promises is that then there's no way to communicate flow control (as with streams). Ironically that's one way a ch.sendToQueue(...);
var await = ch.awaitConfirms();
await.then(function(..) {}); The point being that since it's a promise, you can do this after each publish with no especial penalty. |
There's a first pass at waitForConfirms in master branch now (and an example of using it in the examples directory). |
@pdelanauze Did you have a chance to try |
I'm trying to use a ConfirmChannel with sendToQueue but the callback isn't called. Is that normal?
I've checked the waitForConfirms example and you are using a callback there with |
@ScOut3R I just tried your example, and it appears to work OK. I note that the example doesn't show how you obtain |
NB #103 demonstrates a use for |
Got here by having the same assumption as @pdelanauze by assuming a promise interface for How can I write an application that safely does:
...without publish returning a promise? Should I have know implementation details, such as:
Is any of the above even true? And why am I forced to know this? To me, Any other implementation than a promisified |
No, neither of those are true.
Yes, you have to know about the protocol you're using. Is that really to your detriment? It's like having to know that you need to commit a database transaction before you exit your program. Furthermore, returning a promise from publish doesn't remove that requirement -- you would still have to know to synchronise on that promise (i.e., what it means in terms of the protocol) in specific circumstances. I appreciate that you would like to be shielded from awkward details. I've explained above, and in #62, why it works the way it works. Summary: the return value from |
@squaremo i do get the details, and unfortunately I only know the concepts of the protocol, not its details, and this seems like an implementation detail. This is why I brought up these two issues, which, since both are wrong, show how (unnecessary) hard it is to use For example, what happens with mandatory messages that are being, according to the documentation, "sent back"? Can I detect this from the return value of
If publish does not return a promise, which people obviously expect (I know the documentation says otherwise), the above code will throw an error to the event loop if publish fails. Or should I read errors elsewhere? Also, how do I deal with errors for specific messages? How do I know the message has actually been handled by the server? If you want to keep the current API, which is reasonable, I would like to see something like a Or maybe I am completely missing something :) |
Not really, just some details of the AMQP protocol. I agree with your sentiment that APIs should be as unsurprising as possible. Let me fill in the details and see if I can persuade you that the API is the least surprising it can be, given AMQP's delightful quirks.
Actually it's not just In addition, it's only publish on a So there's a consistent rule: RPCs return promises (or accept callbacks in the callback-oriented API), non-RPCs don't.
They get returned in a set of "return" frames, at some indefinite time after the publish (and possibly other operations). The returned message is a copy of the original, but is treated the same as a new delivery, so is not in general able to be correlated (by the library) with the original message. That all might be OK, except that in general there is no success indication. A confirmation does mean that if the message was going to be returned, it will have been returned already, so you could in principle always use a confirm channel, wait for the confirmation for each message, and make sure there was no returned message in the meantime. It would be dreadfully slow, especially if you're using persistent messages.
No, publish does not get a synchronous response from the server (not even in the case of confirmation); the return value in the API indicates whether that write buffer has room left for more messages. By the way, this write buffer thing may seem like an implementation detail, but it's pretty important. It's quite easy, if you're not paying attention to flow control, to bring Node.JS to its knees, jamming e.g. the contents of a large file into AMQP messages.
There's really only one error that you can make with publish, and that's to address it to an exchange that doesn't exist. In this case, the server closes the channel, which is what triggers the 'error' event. Unless you use confirmations and synchronise on every single message, there's no way to pin it to a specific message (although you can look at the error and see which was the erroneous exchange). In this sense, it's consistent with all other operations, which also close the channel when there's an error. It's just that those are expecting an answer, so it's natural to supply the error in lieu of the answer. Returns (as in undeliverable messages) are not considered errors (in the protocol, and thus in the library). The channel can also be closed by the server if, say, an operator decides they don't like you. So it might not even happen in response to something you've done.
There's not really a "safe on the server". For instance, a message can go straight to a consumer, not resting in a queue (let alone being written to disk), and be confirmed. All that aside, yes one probably could write a
and perhaps treat message returns as errors. |
I'm closing this, since I think I've met the brief of the original issue (with |
After reading the last post, I'm still unclear. Why can't Is this unsafe? var sendIt = new Promise((fulfill, reject) => {
myConfirmChannel.sendToQueue(myQueue, myBuffer, {}, (err, res) => {
if(err){
reject(err);
}else{
fulfill(res);
}
});
}); It's counterintuitive that the method supports a callback but can't return a promise. Edit: to answer my own question: because the return value is immediate and the callback returns later. two values, different times. Got it. I'm just not using the immediate value in this case. |
@matt-cook and others, expanding on @matt-cook answer. I'm currently using a similar implementation
Is that safe ? More clearly : Can I consider "the callback being called with no |
Right now , (v0.2.1) ConfirmChannel#publish / ConfirmChannel#sendToQueue dont seem to return a promise , they only accept a callback ? Not 100% sure about this , but our current testing is returning true even if no callback is supplied ... If our testing is right , would it be worthwhile to return a promise ?
The text was updated successfully, but these errors were encountered: