• notice
  • Congratulations on the launch of the Sought Tech site

Message push interface design (including source code)

What we have to do today is to implement part of the code of the module austin-apiand austin-api-implthe 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 austinprojects, 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-apiDefine the interface for sending messages austin-api-implunder 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 messageTemplateIdgo to the database to find out the information of the entire template, but MessageParamthe parameters passed in by the business itself (the important thing is the parameter information of the receiver and the copy), and codeit 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-apiafter receiving the request, the message is sent MQto

What's the benefit of doing this? Assuming that the service of a certain message times out, austin-apiif 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 msgContentthe 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-apilayer 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-apiIt 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-apiif 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 :


Tags

Technical otaku

Sought technology together

Related Topic

0 Comments

Leave a Reply

+