Skip to content

Commit

Permalink
kie-kogito-docs-557: Add Newsletter subscription use case (#558)
Browse files Browse the repository at this point in the history
* kie-kogito-docs-557: Add Newsletter subscription use case

* Fixing string unification references

* Kaldesai review suggestions

* Update serverlessworkflow/modules/ROOT/pages/use-cases/advanced-developer-use-cases/event-orchestration/newsletter-subscription-example.adoc

Co-authored-by: Ricardo Zanini <[email protected]>

---------

Co-authored-by: Dominik Hanák <[email protected]>
Co-authored-by: Ricardo Zanini <[email protected]>
  • Loading branch information
3 people authored Mar 6, 2024
1 parent 35ccd49 commit 6c8b2c9
Show file tree
Hide file tree
Showing 13 changed files with 634 additions and 16 deletions.
2 changes: 1 addition & 1 deletion serverlessworkflow/antora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,4 @@ asciidoc:
# string unication references
data_index_ref: Data Index
workflow_instance: workflow instance
workflow_instances: ${workflow_instance}s
workflow_instances: workflow instances
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions serverlessworkflow/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
**** xref:use-cases/advanced-developer-use-cases/event-orchestration/consume-produce-events-with-knative-eventing.adoc[]
**** xref:use-cases/advanced-developer-use-cases/event-orchestration/consume-producing-events-with-kafka.adoc[]
**** xref:use-cases/advanced-developer-use-cases/event-orchestration/orchestration-based-saga-pattern.adoc[]
**** xref:use-cases/advanced-developer-use-cases/event-orchestration/newsletter-subscription-example.adoc[]
*** Timeouts
**** xref:use-cases/advanced-developer-use-cases/timeouts/timeout-showcase-example.adoc[]
*** Callbacks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
// Referenced documentation pages
:path_resolution_url: https://quarkus.io/blog/path-resolution-in-quarkus/#defaults

//Common constants
:data_index_ref: Data Index
:workflow_instance: workflow instance
:workflow_instances: {workflow_instance}s

In {product_name} platform there is a dedicated supporting service that stores the data related to the {workflow_instances} and their associated jobs called *{data_index_ref}* service.
This service also provides a GraphQL endpoint allowing users to query that data and perform operations, also known as mutations in GraphQL terms.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
:test_containers_url: https://www.testcontainers.org/
:kubernetes_configmap_url: https://kubernetes.io/docs/concepts/configuration/configmap/
:quarkus_container_image_customizing_url: https://quarkus.io/guides/container-image#customizing
//Common constants
:data_index_ref: Data Index
:workflow_instance: process instance
:workflow_instances: {workflow_instance}s

[#data-index-service]
== {data_index_ref} service deployment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@
:mongo_url: https://www.mongodb.com/
:postgresql_url: https://www.postgresql.org/

//Common constants
:data_index_ref: Data Index
:workflow_instance: process instance
:workflow_instances: {workflow_instance}s


This document describes how you add the {data_index_ref} features to your workflow. You simply need to add the {data_index_ref} extension to the workflow and
the related data will be collected and stored in the database, enabling the GraphQL endpoint to execute queries and perform management operations over the {workflow_instances}.
The example described in this document is based on the link:{kogito_sw_timeouts_showcase_embedded_example_url}[`serverless-workflow-timeouts_showcase_embedded`] example application.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
= Newsletter subscription example in {product_name}

:compat-mode!:
// Metadata:
:description: Newsletter subscription example in {product_name}
:keywords: kogito, workflow, serverless
:flow_newsletter_subscription_url: {kogito_sw_examples_url}/serverless-workflow-newsletter-subscription

This example demonstrates a few features powered by the {product_name} following the Serverless Workflow specification including:

* REST Services calls via OpenAPI definitions
* Pause and resume of a given workflow instance
* Consuming and producing CloudEvents
In a Knative environment, the services involved in this use case can be scaled to zero and resume from the exact stage it was, saving cluster resources in the process.

The figure below illustrates the overall architecture of this use case.

image::use-cases/newsletter-subscription/architecture.png[Architecture]

. Once a new subscription request comes, the flow will evaluate if it's not already subscribed.
. If not, it will attempt to subscribe to the newsletter, the new user and wait for the confirmation.
. Once a new event containing the confirmation arrives, the flow will resume and proceed with the new user subscription.
. Subscriptions not confirmed during a configured period are considered timed-out and automatically removed from the system.
. By the end, a new event containing the details of the subscription is broadcast in the environment, so other actors can react to it.

Here we have the Newsletter Subscription workflow:

.newsletter-subscription-flow workflow
image::use-cases/newsletter-subscription/newsletter-subscription-flow.png[Workflow]

.Newsletter subscription flow workflow definition
[source,json]
----
{
"id": "subscription_flow",
"dataInputSchema": "subscription-schema.json",
"specVersion": "0.8",
"version": "1.0",
"start": "VerifyEmail",
"events": [
{
"kind": "produced",
"type": "new.subscription",
"name": "NewSubscriptionEvent"
},
{
"kind": "consumed",
"type": "confirm.subscription",
"name": "ConfirmSubscriptionEvent"
}
],
"functions": [
{
"name": "subscribeToNewsletter",
"operation": "specs/subscription-service.yaml#subscribe"
},
{
"name": "confirmSubscription",
"operation": "specs/subscription-service.yaml#confirm"
},
{
"name": "deleteSubscription",
"operation": "specs/subscription-service.yaml#delete"
},
{
"name": "verifyEmail",
"operation": "specs/subscription-service.yaml#verify"
}
],
"states": [
{
"name": "VerifyEmail",
"type": "operation",
"actions": [
{
"functionRef": {
"refName": "verifyEmail",
"arguments": {
"email": "${ .email }"
}
}
}
],
"transition": {
"nextState": "ExitIfEmailExists"
}
},
{
"name": "ExitIfEmailExists",
"type": "switch",
"dataConditions": [
{
"condition": "${ .emailExists == true }",
"transition": {
"nextState": "NoSubscription"
}
},
{
"condition": "${ .emailExists == false }",
"transition": {
"nextState": "SubscribeAndWaitForConfirmation"
}
}
]
},
{
"name": "SubscribeAndWaitForConfirmation",
"type": "callback",
"action": {
"functionRef": {
"refName": "subscribeToNewsletter",
"arguments": {
"email": "${ .email }",
"id": "$WORKFLOW.instanceId",
"name": "${ .name }"
}
}
},
"eventRef": "ConfirmSubscriptionEvent",
"transition": {
"nextState": "CheckConfirmation"
},
"timeouts": {
"eventTimeout": "PT3M"
}
},
{
"name" : "CheckConfirmation",
"type" : "switch",
"dataConditions": [
{
"condition": "${ .confirmed == true }",
"transition": "ConfirmSubscription"
}
],
"defaultCondition": {
"transition": "DeleteSubscription"
}
},
{
"name": "ConfirmSubscription",
"type": "operation",
"actions": [
{
"functionRef": {
"refName": "confirmSubscription",
"arguments": {
"email": "${ .email }",
"id": "$WORKFLOW.instanceId",
"name": "${ .name }"
}
}
}
],
"end": {
"produceEvents": [
{
"eventRef": "NewSubscriptionEvent"
}
],
"terminate": true
}
},
{
"name": "DeleteSubscription",
"type": "operation",
"actions": [
{
"functionRef": {
"refName": "deleteSubscription",
"arguments": {
"id": "$WORKFLOW.instanceId"
}
}
}
],
"end": true
},
{
"name": "NoSubscription",
"type": "inject",
"data": {
"subscribed": true
},
"end": true
}
]
}
----

The newsletter-subscription example involves two services:

* Newsletter subscription application. It allows you to create new subscriptions and runs the workflow.
* Newsletter subscription Backend. It allows you to see the pending and approved subscriptions
Both services provide specific user interfaces to allow to track what's going on with the subscriptions

[#workflow_newsletter_subscription_ui]
== The User Interface
As a Quarkus project, you can place the UI resources in the `src/main/resources/META-INF/resources` folder.

The Newsletter Subscription Application (subscription-flow) has a user interface to interact with the workflow without having to rely on the command line to push events or make HTTP requests:

The used resources are available at link:{flow_newsletter_subscription_url}/subscription-flow/src/main/resources/META-INF/resources[Newsletter Subscription Application flow UI resources].

.Newsletter subscription user interface
image::use-cases/newsletter-subscription/newsletter-subscription-ui.png[Newsletter subscription UI]

The Newsletter Subscription backend (subscription-service) has a user interface to see the state of the existing subscriptions

The used resources are available at link:{flow_newsletter_subscription_url}/subscription-service/src/main/resources/META-INF/resources[Subscription service UI resources].

.Newsletter subscription backend user interface
image::use-cases/newsletter-subscription/newsletter-subscription-backend-ui.png[Newsletter subscription backend UI]

== Executing the workflows

In a command terminal, clone the `kogito-examples` repository, navigate to the cloned directory, and follow link:{kogito_sw_examples_url}/serverless-workflow-newsletter-subscription/README.md#running-on-knative[these steps]:

[source, bash]
----
git clone https://github.com/apache/incubator-kie-kogito-examples.git
cd kogito-examples/serverless-workflow-examples/serverless-workflow-newsletter-subscription
----

=== Architecture

The following diagram shows the architecture for this use case:

. Whenever a workflow needs to program a timer for a given timeout, a cloud event is sent to the {job_service_xref}#integration-with-the-workflows[job service] for that purpose.
. When a timer is overdue, a rest call is executed to notify the workflow, which then must execute according to the given state semantic.
. Workflow and job status changes are propagated to the {data_index_xref}[data index service] via cloud events.

.Knative Workflow with Job Service architecture
image::use-cases/newsletter-subscription/newsletter-subscription-Architecture.png[]

* *subscription-flow:* Is the Quarkus Workflow Project that contains the workflows that must be maven built, and deployed into the kubernetes cluster.

* *subscription-service:* Is the Quarkus Workflow Project that contains the backend operations, that must be maven built, and deployed into the kubernetes cluster.

* *jobs-service-postresql:* Is the job service that will be deployed into the kubernetes cluster.

* *data-index-service-postgresql:* Is the data index service that will be deployed into the kubernetes cluster.

* *timeouts-showcase-database:* Is the PostgreSQL instance that will be deployed into the kubernetes cluster.

[NOTE]
====
For simplification purposes, a single database instance is used for both services to store the information about the workflow instances, and the timers. However, in a production environment, it is recommended to have independent database instances.
====


For more information about knative eventing outgoing CloudEvents over HTTP, see xref:use-cases/advanced-developer-use-cases/event-orchestration/consume-produce-events-with-knative-eventing.adoc[].


== Additional resources

* xref:core/timeouts-support.adoc[Timeouts support in {product_name}]
* xref:use-cases/advanced-developer-use-cases/deployments/deploying-on-minikube.adoc[]
* xref:use-cases/advanced-developer-use-cases/event-orchestration/consume-produce-events-with-knative-eventing.adoc[]

include::../../../_common-content/report-issue.adoc[]

0 comments on commit 6c8b2c9

Please sign in to comment.