Skip to content

Commit

Permalink
Merge pull request dapr#4225 from JoshVanL/streaming-subscriptions
Browse files Browse the repository at this point in the history
Adds initial streaming subscriptions docs
  • Loading branch information
hhunter-ms authored Jun 27, 2024
2 parents 1c0c552 + 6f17e1a commit bb72dab
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,13 @@ scopes:

## Subscribe to topics

Dapr provides two methods by which you can subscribe to topics:
Dapr provides three methods by which you can subscribe to topics:

- **Declaratively**, where subscriptions are defined in an external file.
- **Streaming**, where subscriptions are defined in user code.
- **Programmatically**, where subscriptions are defined in user code.

Learn more in the [declarative and programmatic subscriptions doc]({{< ref subscription-methods.md >}}). This example demonstrates a **declarative** subscription.
Learn more in the [declarative, streaming, and programmatic subscriptions doc]({{< ref subscription-methods.md >}}). This example demonstrates a **declarative** subscription.

Create a file named `subscription.yaml` and paste the following:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Pub/sub routing is an implementation of [content-based routing](https://www.ente

While routing can be implemented with code, keeping routing rules external from the application can improve portability.

This feature is available to both the [declarative and programmatic subscription approaches]({{< ref subscription-methods.md >}}).
This feature is available to both the [declarative and programmatic subscription approaches]({{< ref subscription-methods.md >}}), however does not apply to streaming subscriptions.

## Declarative subscription

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,11 @@ Invoke-RestMethod -Method Post -ContentType 'application/json' -Uri 'http://loca
## Subscribing messages in bulk

The bulk subscribe API allows you to subscribe multiple messages from a topic in a single request.
As we know from [How to: Publish & Subscribe to topics]({{< ref howto-publish-subscribe.md >}}), there are two ways to subscribe to topic(s):
As we know from [How to: Publish & Subscribe to topics]({{< ref howto-publish-subscribe.md >}}), there are three ways to subscribe to topic(s):

- **Declaratively** - subscriptions are defined in an external file.
- **Programmatically** - subscriptions are defined in code.
- **Streaming** - *Not supported* for bulk subscribe as messages are sent to handler code.

To Bulk Subscribe to topic(s), we just need to use `bulkSubscribe` spec attribute, something like following:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ scopes:
- checkout
```
## Configuring a dead letter topic with a streaming subscription
```go
var deadLetterTopic = "poisonMessages"
sub, err := cl.Subscribe(context.Background(), client.SubscriptionOptions{
PubsubName: "pubsub",
Topic: "orders",
DeadLetterTopic: &deadLetterTopic,
})
```

## Configuring a dead letter topic with programmatic subscription

The JSON returned from the `/subscribe` endpoint shows how to configure a dead letter topic named `poisonMessages` for messages consumed from the `orders` topic.
Expand Down Expand Up @@ -93,7 +104,7 @@ metadata:
name: deadlettertopics
spec:
topic: poisonMessages
routes:
routes:
rules:
- match:
path: /failedMessages
Expand All @@ -112,4 +123,4 @@ Watch [this video for an overview of the dead letter topics](https://youtu.be/wL
## Next steps

- For more information on resiliency policies, read [Resiliency overview]({{< ref resiliency-overview.md >}}).
- For more information on topic subscriptions, read [Declarative and programmatic subscription methods]({{< ref "pubsub-overview.md#message-subscription" >}}).
- For more information on topic subscriptions, read [Declarative, streaming, and programmatic subscription methods]({{< ref "pubsub-overview.md#message-subscription" >}}).
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,15 @@ In principle, Dapr considers a message successfully delivered once the subscribe

### Receiving messages with topic subscriptions

Dapr applications can subscribe to published topics via two methods that support the same features: declarative and programmatic.
Dapr applications can subscribe to published topics via three subscription types that support the same features: declarative, streaming and programmatic.

| Subscription method | Description |
| Subscription type | Description |
| ------------------- | ----------- |
| **Declarative** | Subscription is defined in an **external file**. The declarative approach removes the Dapr dependency from your code and allows for existing applications to subscribe to topics, without having to change code. |
| **Programmatic** | Subscription is defined in the **user code**. The programmatic approach implements the subscription in your code. |
| **Declarative** | The subscription is defined in an **external file**. The declarative approach removes the Dapr dependency from your code and allows for existing applications to subscribe to topics, without having to change code. |
| **Streaming** | The subscription is defined in the **user code**. Streaming subscriptions are dynamic, meaning they allow for adding or removing subscriptions at runtime. They do not require a subscription endpoint in your application (that is required by both programmatic and declarative subscriptions), making them easy to configure in code. Streaming subscriptions also do not require an app to be configured with the sidecar to receive messages. With streaming subscriptions, since messages are sent to a message handler code, there is no concept of routes or bulk subscriptions. |
| **Programmatic** | Subscription is defined in the **user code**. The programmatic approach implements the static subscription and requires an endpoint in your code. |

For more information, read [about the subscriptions in Subscription Methods]({{< ref subscription-methods.md >}}).
For more information, read [about the subscriptions in Subscription Types]({{< ref subscription-methods.md >}}).

### Reloading topic subscriptions

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
---
type: docs
title: "Declarative and programmatic subscription methods"
linkTitle: "Subscription methods"
title: "Declarative, streaming, and programmatic subscription types"
linkTitle: "Subscription types"
weight: 3000
description: "Learn more about the methods by which Dapr allows you to subscribe to topics."
description: "Learn more about the subscription types that allow you to subscribe to message topics."
---

## Pub/sub API subscription methods
## Pub/sub API subscription types

Dapr applications can subscribe to published topics via two methods that support the same features: declarative and programmatic.
Dapr applications can subscribe to published topics via three subscription types that support the same features: declarative, streaming and programmatic.

| Subscription method | Description |
| Subscription type | Description |
| ------------------- | ----------- |
| [**Declarative**]({{< ref "subscription-methods.md#declarative-subscriptions" >}}) | Subscription is defined in an **external file**. The declarative approach removes the Dapr dependency from your code and allows for existing applications to subscribe to topics, without having to change code. |
| [**Programmatic**]({{< ref "subscription-methods.md#programmatic-subscriptions" >}}) | Subscription is defined in the **application code**. The programmatic approach implements the subscription in your code. |
| [**Streaming**]({{< ref "subscription-methods.md#streaming-subscriptions" >}}) | Subscription is defined in the **application code**. Streaming subscriptions are dynamic, meaning they allow for adding or removing subscriptions at runtime. They do not require a subscription endpoint in your application (that is required by both programmatic and declarative subscriptions), making them easy to configure in code. Streaming subscriptions also do not require an app to be configured with the sidecar to receive messages. |
| [**Programmatic**]({{< ref "subscription-methods.md#programmatic-subscriptions" >}}) | Subscription is defined in the **application code**. The programmatic approach implements the static subscription and requires an endpoint in your code. |

The examples below demonstrate pub/sub messaging between a `checkout` app and an `orderprocessing` app via the `orders` topic. The examples demonstrate the same Dapr pub/sub component used first declaratively, then programmatically.

Expand Down Expand Up @@ -192,6 +193,124 @@ func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err er

The `/checkout` endpoint matches the `route` defined in the subscriptions and this is where Dapr sends all topic messages to.

### Streaming subscriptions

Streaming subscriptions are subscriptions defined in application code that can be dynamically stopped and started at runtime.
Messages are pulled by the application from Dapr. This means no endpoint is needed to subscribe to a topic, and it's possible to subscribe without any app configured on the sidecar at all.
Any number of pubsubs and topics can be subscribed to at once.
As messages are sent to the given message handler code, there is no concept of routes or bulk subscriptions.

> **Note:** Only a single pubsub/topic pair per application may be subscribed at a time.

The example below shows the different ways to stream subscribe to a topic.

{{< tabs Go>}}

{{% codetab %}}

```go
package main
import (
"context"
"log"
"github.com/dapr/go-sdk/client"
)
func main() {
cl, err := client.NewClient()
if err != nil {
log.Fatal(err)
}
sub, err := cl.Subscribe(context.Background(), client.SubscriptionOptions{
PubsubName: "pubsub",
Topic: "orders",
})
if err != nil {
panic(err)
}
// Close must always be called.
defer sub.Close()
for {
msg, err := sub.Receive()
if err != nil {
panic(err)
}
// Process the event
// We _MUST_ always signal the result of processing the message, else the
// message will not be considered as processed and will be redelivered or
// dead lettered.
// msg.Retry()
// msg.Drop()
if err := msg.Success(); err != nil {
panic(err)
}
}
}
```

or

```go
package main
import (
"context"
"log"
"github.com/dapr/go-sdk/client"
"github.com/dapr/go-sdk/service/common"
)
func main() {
cl, err := client.NewClient()
if err != nil {
log.Fatal(err)
}
stop, err := cl.SubscribeWithHandler(context.Background(),
client.SubscriptionOptions{
PubsubName: "pubsub",
Topic: "orders",
},
eventHandler,
)
if err != nil {
panic(err)
}
// Stop must always be called.
defer stop()
<-make(chan struct{})
}
func eventHandler(e *common.TopicEvent) common.SubscriptionResponseStatus {
// Process message here
// common.SubscriptionResponseStatusRetry
// common.SubscriptionResponseStatusDrop
common.SubscriptionResponseStatusDrop, status)
}
return common.SubscriptionResponseStatusSuccess
}
```

{{% /codetab %}}

{{< /tabs >}}

## Demo

Watch [this video for an overview on streaming subscriptions](https://youtu.be/57l-QDwgI-Y?t=841):

<iframe width="560" height="315" src="https://www.youtube.com/embed/57l-QDwgI-Y?si=EJj3uo306vBUvl3Y&amp;start=841" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

### Programmatic subscriptions

The dynamic programmatic approach returns the `routes` JSON structure within the code, unlike the declarative approach's `route` YAML structure.
Expand Down
5 changes: 4 additions & 1 deletion daprdocs/content/en/reference/api/metadata_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Binding | INPUT_BINDING, OUTPUT_BINDING
Each loaded `HttpEndpoint` provides a name to easily identify the Dapr resource associated with the runtime.

### Subscriptions
The metadata API returns a list of pub/sub subscriptions that the app has registered with the Dapr runtime. This includes the pub/sub name, topic, routes, dead letter topic, and the metadata associated with the subscription.
The metadata API returns a list of pub/sub subscriptions that the app has registered with the Dapr runtime. This includes the pub/sub name, topic, routes, dead letter topic, the subscription type, and the metadata associated with the subscription.

### Enabled features
A list of features enabled via Configuration spec (including build-time overrides).
Expand Down Expand Up @@ -114,6 +114,7 @@ topic | string | Topic name.
metadata | object | Metadata associated with the subscription.
rules | [Metadata API Response Subscription Rules](#metadataapiresponsesubscriptionrules)[] | List of rules associated with the subscription.
deadLetterTopic | string | Dead letter topic name.
type | string | Type of the subscription, either `DECLARATIVE`, `STREAMING` or `PROGRAMMATIC`.

<a id="metadataapiresponsesubscriptionrules"></a>**Metadata API Response Subscription Rules**

Expand Down Expand Up @@ -184,6 +185,7 @@ curl http://localhost:3500/v1.0/metadata
],
"subscriptions": [
{
"type": "DECLARATIVE",
"pubsubname": "pubsub",
"topic": "orders",
"deadLetterTopic": "",
Expand Down Expand Up @@ -305,6 +307,7 @@ Get the metadata information to confirm your custom attribute was added:
],
"subscriptions": [
{
"type": "PROGRAMMATIC",
"pubsubname": "pubsub",
"topic": "orders",
"deadLetterTopic": "",
Expand Down

0 comments on commit bb72dab

Please sign in to comment.