-
Notifications
You must be signed in to change notification settings - Fork 11.8k
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
[RIP-37] Add new APIs for producer #3987
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except for the admin operation, the abilities of the new API should be a superset of the old API.
* @return message group, which is optional. | ||
*/ | ||
Optional<String> getMessageGroup(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface need a method getMessageQueue() too.
It may need to send message to the specified MessageQueue.
The case cannot be covered by getMessageGroup().
The priority of getMessageQueue() is bigger than getMessageGroup().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Message here is for producer, user may build message before sending, so Message#getMessageQeue may be not appropriate, but we may consider to add it into the return value of producer sending method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I repeat this:
Except for the admin operation, the abilities of the new API should be a superset of the old API.
The old API could send messages to the specified message queue?
So how to do it in the new API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the abilities of the new API should be a superset of the old API
We don't follow this rule, many useless or low-frequency abilities will be removed in the new APIs, the new APIs don't expand the old APIs.
As for sending messages to a specific queue, we were going to add it in the future version. Consider MessageQueue
is a major model of RocketMQ, we may need to add it in the first version. But, I am not sure it's the right choice, hope more contributors could express opinions on this topic, especially from user perspectives.
* @throws PersistenceException if encountered persistence failure from server. | ||
* @throws TransactionCheckerNotSetException if {@link TransactionChecker} is not set. | ||
*/ | ||
MessageId send(Message message, Transaction transaction) throws ClientException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not the two-phase API!
How about like this :
try {
TransactionMark mark = producer.prepareSend(Message message);
//do process
producer.commit(mark);
} catch(Exception e) {
producer.rollback(mark);
}
Such style is easy to be integrated with db transaction. And the code will not be split.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, we may send more than one message in single transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to send more than one message using such API?
MessageId send(Message message, Transaction transaction)
The old API for the transaction is not naturally two-phase based. It's better to polish it in the new API.
But currently, the new API is just like the old
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to send more than one message using such API? MessageId send(Message message, Transaction transaction)
The old API for the transaction is not naturally two-phase based. It's better to polish it in the new API. But currently, the new API is just like the old
The code example has been added to the javadocs.
apis/src/main/java/org/apache/rocketmq/apis/producer/Producer.java
Outdated
Show resolved
Hide resolved
* @throws NetworkConnectionException if there is a network connection problem. | ||
* @throws PersistenceException if encountered persistence failure from server. | ||
*/ | ||
MessageId send(Message message) throws ClientException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the SendResult?
The client at least needs to know the offset and messagequeue for checking!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SendResult is not essential, because exception may be a better way to indicate the result, but offset and message queue may be considered.
apis/src/main/java/org/apache/rocketmq/apis/message/MessageView.java
Outdated
Show resolved
Hide resolved
apis/src/main/java/org/apache/rocketmq/apis/message/Message.java
Outdated
Show resolved
Hide resolved
apis/src/main/java/org/apache/rocketmq/apis/message/MessageIdVersion.java
Show resolved
Hide resolved
cdd3362
to
bc2a1b9
Compare
e06beb9
to
54fa721
Compare
apis/src/main/java/org/apache/rocketmq/apis/exception/AuthorisationException.java
Show resolved
Hide resolved
apis/src/main/java/org/apache/rocketmq/apis/exception/ClientException.java
Outdated
Show resolved
Hide resolved
* @param topic topic for the message. | ||
* @return the message builder instance. | ||
*/ | ||
MessageBuilder setTopic(String topic); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we remove set prefix the api will be more clean to the developer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, setter/getter style is more common in java, MessageBuilder#topic()
or MessageBuilder#topic(string topicName)
may be more common in cpp.
* | ||
* @return string-formed string id. | ||
*/ | ||
String toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this name is the same as the java origin Object.toString. i think we can change the method name. the origin is anti-parttern naming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#toString()
here aims to emphasize that the implementation must override this method, maybe there is a better solution?
* | ||
* @return the <strong>deep copy</strong> of message body. | ||
*/ | ||
byte[] getBody(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
deep copy seems will harm the performance. but there seems no better return type here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about ByteBuffer here which can be set as unmodifable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about ByteBuffer here which can be set as unmodifable
Nice suggestion.
* @throws TransactionCheckerNotSetException if {@link TransactionChecker} is not set. | ||
* @throws ProducerClosedAlreadyException if producer is closed already. | ||
*/ | ||
Transaction beginTransaction() throws ClientException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe an interface extand producer add some Transaction relate method will be better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please provide some code samples? @WJL3333
*/ | ||
@SuppressWarnings("UnstableApiUsage") | ||
@Override | ||
void close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will close throw exception here?
* @param clientConfiguration client's configuration. | ||
* @return the producer builder instance. | ||
*/ | ||
ProducerBuilder setClientConfiguration(ClientConfiguration clientConfiguration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as Messagebuilder. no set prefix will make api more clean in fluent api call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can find many fluent builder samples in JDK which use the setter pattern, such as https://docs.oracle.com/javase/7/docs/api/java/util/Locale.Builder.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@WJL3333 Lombok doesn't support prefixed builders at the beginning, but this project resolved this issue later, please refer to projectlombok/lombok#1805 (comment), there are many reasons support we use prefixed builders.
* @throws NetworkTimeoutException if encountered network timeout to communicate with server. | ||
* @throws NetworkConnectionException if there is a network connection problem. | ||
*/ | ||
Producer start() throws ClientException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may be move start to the producer.
some case will just build the producer without start.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually producerBuilder#start
could avoid to start producer repeatedly. What's more, a producer which is not started does not make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's strange if we don't have a build
method in a builder interface.
If we only provide a start
method in the producer builder, that means all the producers are started by default, so why we should have a start
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's strange if we don't have a
build
method in a builder interface.If we only provide a
start
method in the producer builder, that means all the producers are started by default, so why we should have astart
?
I agree with the opinon that lack of #build()
may be a little bit weird, let's look at it another way. Is it unnecessary for the user to start producer manually? If so, then I think it's just a naming issue.
* <strong>actually we omit the exception on purpose because {@link TransactionChecker} is the unique right way | ||
* to solve the suspended transaction rather than commit or roll-back repeatedly.</strong> | ||
*/ | ||
void commit(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will commit throw exception need the caller process?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TransactionChecker
is less real-time, which may result in high latency when the commit failed.
apis/src/main/java/org/apache/rocketmq/apis/producer/ProducerBuilder.java
Show resolved
Hide resolved
e36e9ef
to
62a1f28
Compare
/** | ||
* Builder to config and start {@link Producer}. | ||
*/ | ||
public interface ProducerBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a chance to force our developers to set the required fields when building the Producer
or Message
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Builder should throw null field check exception when call build interface.
* @throws PersistenceException if encountered persistence failure from server. | ||
* @throws TransactionCheckerNotSetException if {@link TransactionChecker} is not set. | ||
*/ | ||
MessageView send(Message message, Transaction transaction) throws ClientException; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tons of exceptions are thrown, it's daunting.
I suggest we only declare a ClientException with managed code, request-id, message, etc.
These exceptions are unchecked, which means we don't want our users to use these exceptions to control their logic, so a simple ClientException is enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These exceptions are unchecked, which means we don't want our users to use these exceptions to control their logic, so a simple ClientException is enough.
First of all, exceptions are inevitable. In fact, about the issue that whether to use checked exception or not, maybe no need to prevent users to do responding operation by the exception thrown deliberately? For example, users just want to count how many times the network timeout exception occurred.
In addition, about the issue to use error codes or specific exception, actuall they can all solve the problem in theory, here's my concern
- It is very easy to abuse error code.
- Not all exceptions will have the same parameters, such as requestId, they may only exist in some exceptions.
0f87eb2
to
2d276ba
Compare
apis/src/main/java/org/apache/rocketmq/apis/producer/Producer.java
Outdated
Show resolved
Hide resolved
cbcb38c
to
fc90eac
Compare
c529eec
to
23fa2c2
Compare
This reverts commit 8fc952d.
This reverts commit 8fc952d.
As we mentioned in RIP-37 New and unified APIs, establish a new APIs specifications. we divide it into two independent pull requests.
this pull request is about the producer part.
related issue: #3973