-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
sessionState.ts
152 lines (129 loc) · 5.6 KB
/
sessionState.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
/**
* This sample demonstrates usage of SessionState.
*
* We take for example the context of an online shopping app and see how we can use Session State
* to implement the maintaining of shopping cart information completely on server side i.e.,
* remembering the users' shopped items even if they leave the site and return later.
*
* The scenario in sample walks through user activity of two customers Alice and Bob.
* Alice adds 3 items to the shopping cart and checks out, whereas Bob adds 3 items and leaves without
* checking out to likely return later.
* The session state keeps track of the cart items accordingly.
*
* Setup: To run this sample, you would need session enabled Queue/Subscription.
*
* See https://docs.microsoft.com/azure/service-bus-messaging/message-sessions#message-session-state
* to learn about session state.
*
* @summary Demonstrates usage of SessionState.
*/
import { ServiceBusClient, ServiceBusMessage } from "@azure/service-bus";
// Load the .env file if it exists
import * as dotenv from "dotenv";
dotenv.config();
// Define connection string and related Service Bus entity names here
const connectionString = process.env.SERVICEBUS_CONNECTION_STRING || "<connection string>";
const userEventsQueueName = process.env.QUEUE_NAME_WITH_SESSIONS || "<queue name>";
const sbClient = new ServiceBusClient(connectionString);
export async function main() {
try {
await runScenario();
} finally {
await sbClient.close();
}
}
async function runScenario() {
// User activity data for Alice and Bob
const shoppingEventsDataAlice = [
{ event_name: "Add Item", event_details: "Milk" },
{ event_name: "Add Item", event_details: "Bread" },
{ event_name: "Add Item", event_details: "Eggs" },
{ event_name: "Checkout", event_details: "Success" },
];
const shoppingEventsDataBob = [
{ event_name: "Add Item", event_details: "Pencil" },
{ event_name: "Add Item", event_details: "Paper" },
{ event_name: "Add Item", event_details: "Stapler" },
];
// Simulating user events
await sendMessagesForSession(shoppingEventsDataAlice, "alice");
await sendMessagesForSession(shoppingEventsDataBob, "bob");
await processMessageFromSession("alice");
await processMessageFromSession("alice");
// Displaying snapshot of Alice's shopping cart (SessionState) after processing 2 events
// This will show two items
await getSessionState("alice");
await processMessageFromSession("alice");
await processMessageFromSession("alice");
await processMessageFromSession("bob");
await processMessageFromSession("bob");
await processMessageFromSession("bob");
// Displaying snapshot of Alice's shopping cart (SessionState) after processing remaining events
// This will show null as Alice checksout and cart is cleared
await getSessionState("alice");
// Displaying snapshot of Bob's shopping cart (SessionState) after processing all the events
// This will show three items
await getSessionState("bob");
}
async function getSessionState(sessionId: string) {
// If receiving from a subscription you can use the acceptSession(topic, subscription, sessionId) overload
const sessionReceiver = await sbClient.acceptSession(userEventsQueueName, sessionId);
const sessionState = await sessionReceiver.getSessionState();
if (sessionState) {
// Get list of items
console.log(`\nItems in cart for ${sessionId}: ${sessionState}\n`);
} else {
console.log(`\nNo Items were added to cart for ${sessionId}\n`);
}
await sessionReceiver.close();
}
async function sendMessagesForSession(shoppingEvents: any[], sessionId: string) {
// createSender() can also be used to create a sender for a topic.
const sender = sbClient.createSender(userEventsQueueName);
for (let index = 0; index < shoppingEvents.length; index++) {
const message: ServiceBusMessage = {
sessionId: sessionId,
body: shoppingEvents[index],
subject: "Shopping Step",
};
await sender.sendMessages(message);
}
await sender.close();
}
async function processMessageFromSession(sessionId: string) {
// If receiving from a subscription you can use the acceptSession(topic, subscription, sessionId) overload
const sessionReceiver = await sbClient.acceptSession(userEventsQueueName, sessionId);
const messages = await sessionReceiver.receiveMessages(1, {
maxWaitTimeInMs: 10000,
});
// Custom logic for processing the messages
if (messages.length > 0) {
// Update sessionState
if (messages[0].body.event_name === "Checkout") {
// Clear cart if customer exits, else retain items.
await sessionReceiver.setSessionState(JSON.stringify([]));
} else if (messages[0].body.event_name === "Add Item") {
// Update cart if customer adds items and store it in session state.
const currentSessionState = await sessionReceiver.getSessionState();
let newSessionState: string[] = [];
if (currentSessionState) {
newSessionState = JSON.parse(currentSessionState);
}
newSessionState.push(messages[0].body.event_details);
await sessionReceiver.setSessionState(JSON.stringify(newSessionState));
}
console.log(
`Received message: Customer '${sessionReceiver.sessionId}': '${messages[0].body.event_name} ${messages[0].body.event_details}'`,
);
await sessionReceiver.completeMessage(messages[0]);
} else {
console.log(`No events were received for Customer: ${sessionId}\n`);
}
await sessionReceiver.close();
}
main().catch((err) => {
console.log("Session State - Error occurred: ", err);
process.exit(1);
});