Message push interface design (including source code)
What we have to do today is to implement part of the code of the module austin-api
and austin-api-impl
the module. After this piece is completed, the entire link between the modules will be opened.
Core function of the austin project : send messages
The significance of the project : As long as there is a need to send messages in the company, there should be similar austin
projects, and all kinds of messages should be sent and processed uniformly. This is conducive to the collection of functions and improves the efficiency of business requirements development
Not many BBs, let's start today's topic
01. Interface design
austini-api
Define the interface for sending messages austin-api-impl
under the module, and implement the specific logic under the module. My interface implementation definition:
public interface SendService { /** * 单模板单文案发送接口 * @param sendRequest * @return */ SendResponse send(SendRequest sendRequest); /** * 单模板多文案发送接口 * @param batchSendRequest * @return */ SendResponse batchSend(BatchSendRequest batchSendRequest);}
For externally provided interfaces, in addition to the Single interface, it is better to provide a Batch interface. Because it is very likely that the business side needs to be executed in batches (if there is only a Single interface, then multiple remote calls are required, which is not suitable for business)
The interface parameters I have defined are as follows:
public class SendRequest { /** * 执行业务类型 */ private String code; /** * 消息模板Id */ private Long messageTemplateId; /** * 消息相关的参数 */ private MessageParam messageParam; }
You can messageTemplateId
go to the database to find out the information of the entire template, but MessageParam
the parameters passed in by the business itself (the important thing is the parameter information of the receiver and the copy), and code
it represents the type of business to be executed by the current request (which can be based on the code Expansion, will continue to talk later)
02. Code implementation
As you can see from the process, austin-api
after receiving the request, the message is sent MQ
to
What's the benefit of doing this? Assuming that the service of a certain message times out, austin-api
if the service of the delivery interface is directly called, there may be a risk of time-out and drag down the performance of the entire interface. MQ is here to do asynchronous and decoupling, and to a certain extent resist business traffic.
For the vast majority of sent messages, the business side is not too concerned about whether the sending result can be known when the interface is called , and some channels do not know the sending result when sending (the final result is notified asynchronously). , such as SMS and PUSH push)
Based on the above reasons, it is very reasonable to introduce MQ to carry the traffic of the interface and do asynchronous.
Two days ago, I posted an article on the blog platform " Interviewer: How to Design When the System Requirements Change? ", some netizens commented:
Interviewer: I understand, go back and wait for the notice. ...... leader: Xiao Wang, how is the refactoring plan of our variable system? Xiao Wang: No problem. First, identify the chain of responsibility according to our business, and then deploy scripts in each specific step, and add a service orchestration interface to the upper layer for unified management ... leader: It sounds interesting, today's How are the candidates? Xiao Wang: Don't mention it. He said that he has 5 years of experience in large-scale system design, and he has never used redis. Isn't this the recruiting season? It's enough to recruit two intern tool people to come in and fight for me. leader: Okay, divide the time nodes and milestones, and start the project on confluence. Xiao Wang: Alright.
In this implementation, I also used the chain of responsibility model, and you can go to Gitee to pull the specific and complete code. Many students found that they could not understand the code after pulling the code. You can sort out the roles of the responsibility chain according to the following figure. If you really don’t understand it, I suggest turning over the chain of responsibility article I wrote before (two have already been submitted)
Let's go back to the code implementation, this time the business I implemented is: parameter pre-check -> parameter assembly -> send message
Yeah, I've drawn so many pictures, first give a like and follow a wave first.
In these processes, maybe the next time you pull the code, you will see a " post-check ", or something else. But anyway, with this logic, I no longer have to write all kinds of if else on the same class. Just add an Action at a node and you're done.
(Note: This is the first version of the implementation. I will definitely add logic or comments on the basis later. In fact, I am already writing it, but I usually push the code at a small stage, so remember to star gitee to see the latest code. )
Let’s talk about the pre-check first , mainly to judge whether the template ID is passed in and whether the message parameters are passed in (regular inspection of parameters, if there is a problem, break the link directly, and return to tell the caller that there is a problem)
Next, let's look at the parameter assembly . This part mainly uses the template ID to check the content of the entire template , and then assembles its own TaskInfo (task message) according to the business input parameters .
Some students may have questions❓: Why can't you directly use the POJO of the template? Instead, it needs to be assembled into TaskInfo?
In fact, it is relatively easy to understand. The template is used as the information for the user to configure the message, which is the most primitive information. But we need to do processing when we send it. For example, I want to splicing parameters on the URL link written by the user, I want to replace the placeholder with the real value, I want to add the business ID to the template to track the data, and so on.
To put it bluntly, TaskInfo is template-based, and some platform-specific fields (businessId) are added to the template, and the real content that the user wants to send is parsed out of the template set by the user.
Here, it is worth mentioning the description of msgContent
the field. In the template, the definition of this field in the database annotation is (this field must be stored in the database in JSON format):
`msg_content` varchar(600) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '消息内容 占位符用{$var}表示',
The JSON structure of different channels is different:
SMS: {"content":"","url":""}
Mail: {"content":"","subTitle":""}
Push: {"content":"","subTitle":"","phoneImgUrl":""}
Mini Program: {"content":"","pagePath":"" ......}
The first reaction is that I want to define the fields that all channels may use under TaskInfo. Later, I felt that this was not very good-looking, so I defined various Model
(different sending channels have their own content models)
So, I use reflection to map when assembling TaskInfo, and replace the placeholder with the help ofPropertyPlaceholderHelper
Sending is very simple. I directly serialize TaskInfo into JSON, and then deserialize it when reading.
It is worth noting that because TaskInfo uses ContentModel to store the content model, we need to write the "class information" when serializing JSON, otherwise the data of subclasses will not be available when deserializing.
03. Summary
For projects with source code, I am actually reluctant to explain the code I wrote every step of the way. Because I don't think my writing is that complicated, and there is no dazzling element in it.
But since I pushed the code, after reminding everyone in the group to follow the project, several people gave me feedback that they didn't understand it well, so I'll talk about it separately.
Looking back, in fact, after the austin-api
layer receives the request, before sending the message to MQ, the operation here is very simple. In fact, it is possible to do general business here (such as the function of general deduplication), but after my consideration, it is still not suitable.
austin-api
It is an access layer. So far, it only reads the configuration from the database through the id, and there is no time-consuming operation (which means that the concurrency it can carry is extremely large). Assuming that there will be a bottleneck in the future to read the database by ID, we can also consider fetching the configuration from Redis or even local memory.
This is determined by the business: there are often not many changes to a template, even if the cache has strong consistency problems, but that little time is completely acceptable.
Question : Why do I need MQ to send a message?
Answer : Sending a message is actually calling the API provided by each service. Assuming that the service of a message times out, austin-api
if the service is called directly, there is a risk of timeout , which will drag down the performance of the entire interface. MQ is here to do asynchronous and decoupling, and to a certain extent resist business traffic.
Question : Can you briefly describe what the access layer does?
Answer :
0 Comments