# How SDS Clients Receive Downgrade Event Notifications: Implementation Guide

> Learn how SDS clients receive downgrade event notifications via a publish-subscribe mechanism. This guide details the implementation using DowngradeActionListener and SdsDowngradeActionNotify for asynchronous event dispatch.

- Repository: [DiDi/sds](https://github.com/didi/sds)
- Tags: how-to-guide
- Published: 2026-02-28

---

**SDS clients receive downgrade event notifications through a publish-subscribe mechanism that uses the `DowngradeActionListener` interface and the `SdsDowngradeActionNotify` class to dispatch events asynchronously via a dedicated thread pool.**

The DiDi SDS (Service Degradation System) client library provides a robust notification system that allows applications to react to service degradation events in real-time. By implementing the `DowngradeActionListener` interface and registering with the central notification hub, clients can receive asynchronous alerts whenever a service point is downgraded. This guide explains the internal architecture and implementation details based on the source code in the `didi/sds` repository.

## How Downgrade Notifications Work in SDS

The notification system follows a four-stage pipeline: interface definition, listener registration, event triggering, and asynchronous dispatch.

### The DowngradeActionListener Interface

Clients must implement the `DowngradeActionListener` interface located in [`sds-client/src/main/java/com/didiglobal/sds/client/listener/DowngradeActionListener.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/listener/DowngradeActionListener.java). This interface defines a single callback method that receives three parameters whenever a downgrade occurs:

- **`point`** – The identifier of the degraded service point
- **`downgradeActionType`** – An enum (`DowngradeActionType`) describing the trigger reason (e.g., `THRESHOLD`, `DELAY`, `MANUAL`)
- **`time`** – The timestamp when the downgrade was triggered

```java
public interface DowngradeActionListener {
    void downgradeAction(String point,
                         DowngradeActionType downgradeActionType,
                         Date time);
}

```

### Registering Listeners with SdsDowngradeActionNotify

Listeners register through the static `SdsDowngradeActionNotify` class found in [`sds-client/src/main/java/com/didiglobal/sds/client/config/SdsDowngradeActionNotify.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/config/SdsDowngradeActionNotify.java). The registration method is thread-safe and stores listeners in a `CopyOnWriteArrayList` to prevent concurrency issues during iteration.

```java
SdsDowngradeActionNotify.addDowngradeActionListener(myListener);

```

### Event Triggering and Asynchronous Dispatch

When the client determines a request must be downgraded, the `CommonSdsClient` class invokes `addDowngradeCount`. This method, located at lines 69-76 in [`sds-client/src/main/java/com/didiglobal/sds/client/CommonSdsClient.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/CommonSdsClient.java), updates the internal counter and triggers the notification system:

```java
private void addDowngradeCount(String point,
                               long time,
                               DowngradeActionType downgradeActionType) {
    SdsPowerfulCounterService.getInstance().downgradeAddAndGet(point, time);
    SdsDowngradeActionNotify.notify(point, downgradeActionType, new Date(time));
}

```

The `SdsDowngradeActionNotify.notify` method enqueues tasks to a dedicated fixed-size thread pool (`notifyPool`). Each registered listener executes in a background thread, isolating the main request flow from listener latency or errors:

```java
notifyPool.execute(() -> {
    for (DowngradeActionListener listener : listeners) {
        try {
            listener.downgradeAction(point, downgradeActionType, time);
        } catch (Exception e) {
            logger.warn(...);
        }
    }
});

```

## Implementation Examples

### Lambda-Based Listener Registration

For simple implementations, use a lambda expression to register the listener directly:

```java
import com.didiglobal.sds.client.config.SdsDowngradeActionNotify;
import com.didiglobal.sds.client.enums.DowngradeActionType;

SdsDowngradeActionNotify.addDowngradeActionListener(
    (point, downgradeActionType, time) -> {
        System.out.println(
            String.format("Downgrade detected: point=%s, type=%s, at=%s",
                          point, downgradeActionType, time));
        // Custom handling, e.g., push to monitoring system
    });

```

A complete working example appears in the demo Spring Boot application at [`sds-example/sds-apache-dubbo-example/src/main/java/com/didiglobal/sds/example/DemoServiceApplication.java`](https://github.com/didi/sds/blob/main/sds-example/sds-apache-dubbo-example/src/main/java/com/didiglobal/sds/example/DemoServiceApplication.java).

### Class-Based Listener Implementation

For complex logic, implement the interface as a separate class:

```java
import com.didiglobal.sds.client.listener.DowngradeActionListener;
import com.didiglobal.sds.client.enums.DowngradeActionType;
import java.util.Date;

public class MyDowngradeListener implements DowngradeActionListener {
    @Override
    public void downgradeAction(String point,
                               DowngradeActionType downgradeActionType,
                               Date time) {
        // Example: send alert to external service
        AlertService.send(point, downgradeActionType, time);
    }
}

```

Register the instance using the same static method:

```java
SdsDowngradeActionNotify.addDowngradeActionListener(new MyDowngradeListener());

```

## Summary

- **Implement `DowngradeActionListener`** to define custom logic for handling downgrade events in [`sds-client/src/main/java/com/didiglobal/sds/client/listener/DowngradeActionListener.java`](https://github.com/didi/sds/blob/main/sds-client/src/main/java/com/didiglobal/sds/client/listener/DowngradeActionListener.java)
- **Register listeners** via `SdsDowngradeActionNotify.addDowngradeActionListener()` for thread-safe addition to a `CopyOnWriteArrayList`
- **Events trigger** in `CommonSdsClient.addDowngradeCount()` when the system decides to downgrade a service point
- **Asynchronous dispatch** occurs through a dedicated thread pool in `SdsDowngradeActionNotify.notify()`, ensuring non-blocking execution with exception isolation

## Frequently Asked Questions

### How do I register multiple listeners for downgrade events?

Call `SdsDowngradeActionNotify.addDowngradeActionListener()` multiple times with different listener instances. The underlying storage uses a `CopyOnWriteArrayList`, so you can safely register listeners from multiple threads without synchronization concerns.

### What happens if a listener throws an exception during notification?

The notification system wraps each listener invocation in a try-catch block within the `notifyPool` execution loop. If a listener throws an exception, the system logs a warning and continues processing the remaining listeners, ensuring that one faulty listener cannot break the notification chain for others.

### Where exactly are downgrade events triggered in the source code?

Downgrade events originate in [`CommonSdsClient.java`](https://github.com/didi/sds/blob/main/CommonSdsClient.java) at lines 69-76 inside the `addDowngradeCount` method. This method is invoked internally when the client decides a request must be downgraded based on threshold, delay, or manual configuration settings.

### Is the listener notification synchronous or asynchronous?

Notification is strictly asynchronous. The `SdsDowngradeActionNotify.notify()` method submits tasks to a fixed-size thread pool (`notifyPool`), allowing the main request processing thread to continue immediately while listeners execute in background threads.