Hello people!!! Today I am writing this blog to share my experience of using the Azure Web Pub-Sub...
Hello people!!! Today I am writing this blog to share my experience of using the Azure Web Pub-Sub service within Azure Function to send real time messages to my React application.
Many a times, we have a requirement to do some processing asynchronously behind the scenes so that we don't block user's activities on the site.
I came across a similar situation where I was working on a chatbot application. This application has a feature that allows a user to upload a file and then train the file on a specific model and then once the file is trained successfully, the user should be able to query the trained data and get responses from it. Very much similar to what we do in chatgpt.
So the requirement was as below:
Now, while the file is getting trained asynchronously, the user should be able to continue his/her conversation with rest of the available data.
So, then when should the user query for the data that he/she just uploaded as a file??? The answer to this is whenever the file is processed successfully behind the scenes, there should be some indication to the user saying that your file is now trained successfully and is ready to serve requests.
Here comes the concept of a PubSub notification. When the file is processed or trained, the PubSub service will publish a message. That is what Pub stands for. And this published message should be subscribed by some service/resource to receive it which is termed as Sub. So PubSub stands for Publish and Subscribe .
You can use WebSocket connection from your frontend application to stay connected to your publisher service so that you can receive real time messages.
In my case, the publisher is Azure function and the subscriber is React application.
Below is how the service will look like when created successfully
Go to the Keys section and see that there are connection strings available. The primary connection string is to be used while establishing connection. So keep a note of it.
An Azure function is an event driven, serverless compute where you can write less code to save costs and maintain the infrastructure. Read more here
So, now my azure function is responsible to read the file from Azure storage and then pass the file to an API endpoint to train it.
As, the function is event driven, I have to add two functions in my function app. One is the Blob Storage Trigger which executes whenever a new file is uploaded to the specific storage. And the other is the HTTP Trigger which helps in keeping the Websocket http connection open from the React app to the Azure function.
You have to create a function app in Azure and then add the functions to that function app.
Steps to create the function app:
Below is my code structure for Azure function:
The AiTrain function is a blob storage trigger function and Negotiate is the HTTP trigger function. I am using typescript.
This function is responsible to return the connection object to the subscriber. So, the index.ts file in this function has below code.
module.exports = function (context, req, connection) {
context.res = { body: connection };
context.done();
};
And in the function.json file, it has below settings:
{
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
},
{
"type": "webPubSubConnection",
"name": "connection",
"hub": "notification",
"direction": "in"
}
],
"scriptFile": "../dist/Negotiate/index.js"
}
This function is responsible to train the uploaded file and publish a message after success.
import { AzureFunction, Context } from '@azure/functions';
const blobTrigger: AzureFunction = async function (
context: Context,
myBlob: string
): Promise<void> {
try {
context.log('TypeScript Blob trigger function');
const blobURI = decodeURIComponent(context.bindingData.uri);
// file processing logic
//Azure web pubsub actions
const actions = {
actionName: 'sendToAll',
data: `File processing complete!`,
dataType: 'text',
};
context.bindings.actions = actions;
// No asynchronous operations, so we can return a resolved Promise
return Promise.resolve();
}
} catch (error: unknown) {
console.error(error);
}
};
export default blobTrigger;
The function.json file has below code:
{
"bindings": [
{
"name": "myBlob",
"type": "blobTrigger",
"direction": "in",
"path": "files/",
"connection": "dev_STORAGE"
},
{
"type": "webPubSub",
"name": "actions",
"hub": "notification",
"direction": "out"
}
],
"scriptFile": "../dist/AiTrain/index.js"
}
This completes the first part of publishing a message from Azure function.
In order to subscribe the messages from the React application, all you need to do is establish a Websocket connection in your code.
Below is my react code that establishes a Websocket connection to the azure function.
useEffect(() => {
const connect = async () => {
const res = await fetch(`$/api/negotiate`);
const { url, accessToken } = await res.json();
const ws = new WebSocket(url);
ws.onopen = () => console.log('connected');
ws.onmessage = (event:any) => {
console.log(JSON.stringify(event.data));
//Code Logic
};
};
connect();
}, []);
We have to call the negotiate endpoint to keep the React app connected to the Azure function.
And that's all. You can see the console messages to see the event object that has the data sent from the Azure function. You can choose any component to display this data as a notification to the user.
In conclusion, Azure Web PubSub when coupled with Azure Functions and a React application opens up exciting possibilities for real-time, scalable, and interactive web experiences. We've explored how seamlessly these components integrate to create a dynamic communication channel between the server and client, enabling instant updates and collaborative features.
Keep experimenting, pushing the boundaries, and discovering new ways to leverage Azure Web PubSub. The possibilities are vast.