Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a Lightweight SMS Platform Service from Scratch

Tech May 10 3

Motivation

In 2018, while serving as an architect, I participated in the reconstruction of an SMS platform. The SMS sending scenarios included repayment business, CRM, promotional activities, and more.

Different technical teams used varying client modes to send SMS messages, which lacked standardization:

  • Using Alibaba Cloud's SMS SDK for sending
  • Direct SMS sending via examples provided by Yimei
  • Using Lvcheng's SMS SDK
  • The architecture team's SMS SDK, similar to SMS4J's design approach, supporting Yimei and Lvcheng SMS sending

The client mode approach in multi-team collaboration scenarios has significant drawbacks:

Maintenance Burden

If operations discontinue using a particular SMS channel, many teams would be affected and would need to modify configurations and redeploy, resulting in high time costs.

Limited Advanced Functionality Support

Certain features are difficult to implement in client mode. For example, when a client experiences timeout issues with a third-party channel due to network issues, the system needs to route SMS to a backup channel to ensure delivery success rates.

Therefore, in multi-team collaboration scenarios, the SMS service should adopt a server-side mode.

Architecture Design

The project targets helping junior to mid-level engineers understand architecture design, so the implementation follows a monolithic application pattern.

The SMS platform consists of two components that can be deployed independently or combined:

1. Frontend: admin-ui

The console module is a Vue project. Administrators can manage applications, channels, SMS records, and templates after logging in.

2. Backend: admin-web

The backend module is divided into five layers based on functionality:

  • Request Controller Layer
  • Business Service Layer
  • Command Handler
  • Third-party Channel Adapter Plugins
  • Database Access Layer

The design mimics Tencent Cloud's SMS service architecture:

  1. Following Tencent Cloud's SDK design pattern to provide simple SMS sending methods (single send, batch send, marketing single send, marketing batch send, template single send, template batch send)
  2. Designing an SMS service API endpoint to receive requests and push SMS data to a message queue
  3. Worker services consuming messages and calling different channel provider interfaces using load balancing algorithms
  4. Console for viewing SMS sending records and configuring channel providers and templates

After completion, the SMS platform met business requirements. SMS management became centralized, improving the efficiency of business teams integrating the SMS service.

Core Design Principles

Based on industry observations, the core challenges in SMS services typically involve:

  1. Boundary issues between SMS services and business services - Adding excessive business logic to the SMS platform causes feature bloat and introduces hidden risks.
  2. Inflexible third-party channel switching - When operations need to switch from channel A to channel B, poor code abstraction makes maintenance costly.

For this lightweight SMS service, the following features are essential:

1. Simple SMS SDK Supporting Template-based Sending

Business services don't care which third-party channel sends the SMS, only that it's delivered successfully. The SDK provides the core interface: send SMS by template ID.

Alibaba Cloud, Tencent Cloud, and Huawei Cloud all provide template-based SMS APIs. For unified management, the platform only supports template-based sending. The SMS platform provides appKey and appSecret for business services, with SDK and server communication via a fixed protocol.

2. Template Management Support

All three providers offer signature and template management APIs. The platform supports manual binding of SMS templates, meaning singatures and templates must first be applied for through Alibaba Cloud or Tencent Cloud, then bound to platform-created templates.

3. Adapter Pattern for Third-party Channel Maintenance

Inspired by canal's adapter module, third-party SMS channel APIs are isolated as separate modules. This significantly improves code maintainability.

Deployment Guide

Environment Setup

1. Database Initialization

Create database tech_platform and execute the SQL scripts in the doc/sql directory.

2. Configuration

Download platform-sms-admin.tar.gz from the Release page. After extraction, edit the application.yml file in the conf directory.

3. Startup

bin/startup.sh

Operational Workflow

1. Login

After starting the service, access: http://localhost:8089. Default credentials are stored in the application.yml file.

2. Create Application

Application information includes name, appKey, appSecret, and remarks. The appKey and secret are required when using the client SDK.

3. Configure Third-party SMS Channel

Note: Tencent Cloud's SDK requires APPID in requests, so in the Beta version, appId is stored in additional properties.

4. Create Template

In the template management module, click the "New Template" button. The signature name must match the channel-applied signature exactly.

After creating the template, channel binding is required. First, create the SMS template on the third-party channel, then submit the binding.

Client Integration

1. Add Dependency

<dependency>
    <groupId>com.courage</groupId>
    <artifactId>platform-sms-client</artifactId>
    <version>${parent.version}</version>
</dependency>

2. Client Configuration

Configure in application.yml:

sms:
  smsServerUrl: http://localhost:8089
  appKey: qQjEiFzn80v8VM4h
  appSecret: 9c465ece754bd26a9be77f3d0e2606bd

Create the configuration class:

@Configuration
public class SmsConfiguration {

    @Value("${sms.smsServerUrl}")
    private String serverUrl;

    @Value("${sms.appKey}")
    private String key;

    @Value("${sms.appSecret}")
    private String secret;

    @Bean
    public SmsSenderClient createClient() {
        SmsConfig config = new SmsConfig();
        config.setAppKey(key);
        config.setSmsServerUrl(serverUrl);
        config.setAppSecret(secret);
        return new SmsSenderClient(config);
    }
}

3. Sending SMS

@Autowired
private SmsSenderClient smsSenderClient;

@GetMapping("/test")
public String test() {
    String mobile = "15011319235";
    String templateId = "555829270636703745";
    Map<String, String> params = new HashMap<>();
    params.put("code", "1234");
    params.put("time", "10");
    SmsSenderResult result = smsSenderClient.sendSmsByTemplateId(mobile, templateId, params);
    System.out.println("result:" + JSON.toJSONString(result));
    return "SMS sent successfully";
}

Project Highlights

This project serves as an architecture learning resource. Key takeaways include:

  1. Designing a lightweight client SDK
  2. Understanding SPI mechanisms and the adapter pattern
  3. Implementing appropriate threading models

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.