Scheduled Bulk SMS with Azure Communication Services, Spring Boot, Spring Batch & Quartz


Here's a short explanation of each step:

  1. User starts the Spring Boot Application.
  2. SpringBoot schedules a batch job using Quartz Scheduler (runs every 5 minutes).
  3. Quartz triggers the batch job.
  4. Batch fetches customer data (phone numbers and messages) from the Database.
  5. Batch sends the SMS messages using the SMS Service.
  6. SMS Service interacts with Azure Communication Services (ACS) to send the SMS.
  7. ACS returns the delivery status to the SMS Service.
  8. SMS Service sends the status back to Batch.
  9. Batch notifies Quartz about job completion.
  10. Quartz informs SpringBoot that the job is complete.

This diagram visually represents the flow of actions in the system, detailing the interaction between different components and how the batch SMS process is executed and monitored.

Here's a step-by-step guide on how to schedule and send batch SMS using Azure Communication Services (ACS) with Spring Boot, Quartz Scheduler, and Spring Batch.


1. Prerequisites

Ensure you have:

  • Azure Subscription
  • Azure Communication Services (ACS) resource (to send SMS)
  • Spring Boot Application
  • Quartz Scheduler (for scheduling)
  • Spring Batch (for batch processing)
  • Maven/Gradle

2. Set Up Azure Communication Services (ACS)

Step 1: Create ACS Resource

  1. Sign in to the Azure Portal.
  2. Search for "Azure Communication Services" and create a new resource.
  3. Go to the Keys section and copy the Connection String.
  4. Purchase a phone number (needed to send SMS).

Step 2: Add Dependencies to pom.xml

<dependencies>
    <!-- Azure Communication Services SMS SDK -->
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-communication-sms</artifactId>
        <version>1.1.30</version>
    </dependency>

    <!-- Quartz Scheduler -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-quartz</artifactId>
    </dependency>

    <!-- Spring Batch -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-batch</artifactId>
    </dependency>

    <!-- Database (H2 for simplicity) -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

3. Configure ACS SMS Sending Service

Step 1: Create SMS Sender Service

import com.azure.communication.sms.SmsClient;
import com.azure.communication.sms.SmsClientBuilder;
import com.azure.communication.sms.models.SmsSendResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class SmsService {
    
    private final SmsClient smsClient;

    public SmsService(@Value("${azure.communication.connection-string}") String connectionString) {
        this.smsClient = new SmsClientBuilder().connectionString(connectionString).buildClient();
    }

    public void sendSmsBatch(List<String> phoneNumbers, String message) {
        for (String number : phoneNumbers) {
            SmsSendResult result = smsClient.send("+1234567890", number, message); // Replace with your ACS phone number
            System.out.println("Sent SMS to " + number + " Status: " + result.getSuccessful());
        }
    }
}

Step 2: Configure application.properties

azure.communication.connection-string=YOUR_ACS_CONNECTION_STRING

4. Implement Spring Batch for Bulk SMS Processing

Step 1: Create Customer Entity

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String phoneNumber;
    private String message;
}

Step 2: Define CustomerRepository

import com.example.sms.model.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> { }

Step 3: Create CustomerItemReader

import com.example.sms.model.Customer;
import org.springframework.batch.item.ItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.example.sms.repository.CustomerRepository;
import java.util.Iterator;
import java.util.List;

@Component
public class CustomerItemReader implements ItemReader<Customer> {

    @Autowired
    private CustomerRepository customerRepository;

    private Iterator<Customer> customerIterator;

    @Override
    public Customer read() {
        if (customerIterator == null || !customerIterator.hasNext()) {
            List<Customer> customers = customerRepository.findAll();
            customerIterator = customers.iterator();
        }
        return customerIterator.hasNext() ? customerIterator.next() : null;
    }
}

Step 4: Define CustomerProcessor

import com.example.sms.model.Customer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;

@Component
public class CustomerProcessor implements ItemProcessor<Customer, Customer> {
    @Override
    public Customer process(Customer customer) {
        return customer;
    }
}

Step 5: Implement SmsItemWriter

import com.example.sms.model.Customer;
import com.example.sms.service.SmsService;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class SmsItemWriter implements ItemWriter<Customer> {

    @Autowired
    private SmsService smsService;

    @Override
    public void write(List<? extends Customer> customers) {
        List<String> phoneNumbers = customers.stream().map(Customer::getPhoneNumber).collect(Collectors.toList());
        String message = "This is a batch SMS test.";
        smsService.sendSmsBatch(phoneNumbers, message);
    }
}

Step 6: Configure Batch Job

import com.example.sms.model.Customer;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.batch.item.database.JpaItemWriter;

import javax.persistence.EntityManagerFactory;

@Configuration
@EnableBatchProcessing
public class BatchConfig {

    @Bean
    public Job sendSmsJob(JobBuilderFactory jobBuilderFactory, Step sendSmsStep) {
        return jobBuilderFactory.get("sendSmsJob").start(sendSmsStep).build();
    }

    @Bean
    public Step sendSmsStep(StepBuilderFactory stepBuilderFactory, 
                            CustomerItemReader reader, 
                            CustomerProcessor processor, 
                            SmsItemWriter writer) {
        return stepBuilderFactory.get("sendSmsStep")
                .<Customer, Customer>chunk(10)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }
}

5. Schedule Batch Job Using Quartz

Step 1: Create Quartz Job

import org.springframework.batch.core.Job;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class SmsBatchScheduler {

    private final JobLauncher jobLauncher;
    private final Job sendSmsJob;

    public SmsBatchScheduler(JobLauncher jobLauncher, Job sendSmsJob) {
        this.jobLauncher = jobLauncher;
        this.sendSmsJob = sendSmsJob;
    }

    @Scheduled(cron = "0 0/5 * * * ?") // Runs every 5 minutes
    public void runBatchJob() throws Exception {
        jobLauncher.run(sendSmsJob, new org.springframework.batch.core.JobParameters());
    }
}

6. Run the Application

mvn spring-boot:run

This will schedule batch SMS sending every 5 minutes.


Conclusion

This setup allows you to: ✅ Store phone numbers and messages in a database
✅ Use Spring Batch for bulk SMS processing
✅ Schedule jobs using Quartz
✅ Send SMS using Azure Communication Services

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

Java, Spring Boot Mini Project - Library Management System - Download

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete