Skip to content

Latest commit

 

History

History
402 lines (300 loc) · 13.6 KB

signalr-quickstart-azure-functions-python.md

File metadata and controls

402 lines (300 loc) · 13.6 KB
titledescriptionauthorms.authorms.datems.topicms.servicems.devlangms.customzone_pivot_groups
Azure SignalR Service serverless quickstart - Python
A quickstart for using Azure SignalR Service and Azure Functions to create an App showing GitHub star count using Python.
vicancy
lianwei
01/23/2024
quickstart
azure-signalr-service
python
devx-track-python, mode-api
python-mode-functions

Quickstart: Create a serverless app with Azure Functions and Azure SignalR Service in Python

Get started with Azure SignalR Service by using Azure Functions and Python to build a serverless application that broadcasts messages to clients. You'll run the function in the local environment, connecting to an Azure SignalR Service instance in the cloud. Completing this quickstart incurs a small cost of a few USD cents or less in your Azure Account.

Note

You can get the code in this article from GitHub.

[!INCLUDE Connection string security]

Prerequisites

This quickstart can be run on macOS, Windows, or Linux. You will need the following:

PrerequisiteDescription
An Azure subscriptionIf you don't have an Azure subscription, create an Azure free account
A code editorYou'll need a code editor such as Visual Studio Code.
Azure Functions Core ToolsRequires version 2.7.1505 or higher to run Python Azure Function apps locally.
Python 3.7+Azure Functions requires Python 3.7+. See Supported Python versions.
AzuriteSignalR binding needs Azure Storage. You can use a local storage emulator when a function is running locally.
Azure CLIOptionally, you can use the Azure CLI to create an Azure SignalR Service instance.

Create an Azure SignalR Service instance

[!INCLUDE Create instance]

::: zone pivot="python-mode-decorators"

Create the Azure Function project

Create a local Azure Function project.

  1. From a command line, create a directory for your project.
  2. Change to the project directory.
  3. Use the Azure Functions func init command to initialize your function project.
# Initialize a function project func init --worker-runtime python

Create the functions

After you initialize a project, you need to create functions. This project requires three functions:

  • index: Hosts a web page for a client.
  • negotiate: Allows a client to get an access token.
  • broadcast: Uses a time trigger to periodically broadcast messages to all clients.

When you run the func new command from the root directory of the project, the Azure Functions Core Tools appends the function code in the function_app.py file. You'll edit the parameters ad content as necessary by replacing the default code with the app code.

Create the index function

You can use this sample function as a template for your own functions.

Open the file function_app.py. This file will contain your functions. First, modify the file to include the necessary import statements, and define global variables that we will be using in the following functions.

importazure.functionsasfuncimportosimportrequestsimportjsonapp=func.FunctionApp() etag=''start_count=0
  1. Add the function index by adding the following code
@app.route(route="index", auth_level=func.AuthLevel.ANONYMOUS)defindex(req: func.HttpRequest) ->func.HttpResponse: f=open(os.path.dirname(os.path.realpath(__file__)) +'/content/index.html') returnfunc.HttpResponse(f.read(), mimetype='text/html')

This function hosts a web page for a client.

Create the negotiate function

Add the function negotiate by adding the following code.

[!INCLUDE Connection string security comment]

@app.route(route="negotiate", auth_level=func.AuthLevel.ANONYMOUS, methods=["POST"])@app.generic_input_binding(arg_name="connectionInfo", type="signalRConnectionInfo", hubName="serverless", connectionStringSetting="AzureSignalRConnectionString")defnegotiate(req: func.HttpRequest, connectionInfo) ->func.HttpResponse: returnfunc.HttpResponse(connectionInfo)

This function allows a client to get an access token.

Create a broadcast function.

Add the function broadcast by adding the following code

@app.timer_trigger(schedule="*/1 * * * *", arg_name="myTimer",run_on_startup=False,use_monitor=False)@app.generic_output_binding(arg_name="signalRMessages", type="signalR", hubName="serverless", connectionStringSetting="AzureSignalRConnectionString")defbroadcast(myTimer: func.TimerRequest, signalRMessages: func.Out[str]) ->None: globaletagglobalstart_countheaders= {'User-Agent': 'serverless', 'If-None-Match': etag} res=requests.get('https://api.github.com/repos/azure/azure-functions-python-worker', headers=headers) ifres.headers.get('ETag'): etag=res.headers.get('ETag') ifres.status_code==200: jres=res.json() start_count=jres['stargazers_count'] signalRMessages.set(json.dumps({ 'target': 'newMessage', 'arguments': [ 'Current star count of https://api.github.com/repos/azure/azure-functions-python-worker is: '+str(start_count) ] }))

This function uses a time trigger to periodically broadcast messages to all clients. ::: zone-end

::: zone pivot="python-mode-configuration"

Create the Azure Function project

Create a local Azure Function project.

  1. From a command line, create a directory for your project.
  2. Change to the project directory.
  3. Use the Azure Functions func init command to initialize your function project.
# Initialize a function project func init --worker-runtime python --model v1

Create the functions

After you initialize a project, you need to create functions. This project requires three functions:

  • index: Hosts a web page for a client.
  • negotiate: Allows a client to get an access token.
  • broadcast: Uses a time trigger to periodically broadcast messages to all clients.

When you run the func new command from the root directory of the project, the Azure Functions Core Tools creates default function source files and stores them in a folder named after the function. You'll edit the files as necessary replacing the default code with the app code.

Create the index function

You can use this sample function as a template for your own functions.

  1. Run the following command to create the index function.
func new -n index -t HttpTrigger
  1. Edit index/function.json and replace the contents with the following json code:
{ "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "$return" } ] }
  1. Edit index/_init_.py and replace the contents with the following code:
importosimportazure.functionsasfuncdefmain(req: func.HttpRequest) ->func.HttpResponse: f=open(os.path.dirname(os.path.realpath(__file__)) +'/../content/index.html') returnfunc.HttpResponse(f.read(), mimetype='text/html')

Create the negotiate function

  1. Run the following command to create the negotiate function.
func new -n negotiate -t HttpTrigger
  1. Edit negotiate/function.json and replace the contents with the following json code:
{ "scriptFile": "__init__.py", "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "post" ] }, { "type": "http", "direction": "out", "name": "$return" }, { "type": "signalRConnectionInfo", "name": "connectionInfo", "hubName": "serverless", "connectionStringSetting": "AzureSignalRConnectionString", "direction": "in" } ] }
  1. Edit negotiate/_init_.py and replace the contents with the following code:
importazure.functionsasfuncdefmain(req: func.HttpRequest, connectionInfo) ->func.HttpResponse: returnfunc.HttpResponse(connectionInfo)

Create a broadcast function.

  1. Run the following command to create the broadcast function.
func new -n broadcast -t TimerTrigger # install requests pip install requests
  1. Edit broadcast/function.json and replace the contents with the following code:
{ "scriptFile": "__init__.py", "bindings": [ { "name": "myTimer", "type": "timerTrigger", "direction": "in", "schedule": "*/5 * * * * *" }, { "type": "signalR", "name": "signalRMessages", "hubName": "serverless", "connectionStringSetting": "AzureSignalRConnectionString", "direction": "out" } ] }
  1. Edit broadcast/_init_.py and replace the contents with the following code:
importrequestsimportjsonimportazure.functionsasfuncetag=''start_count=0defmain(myTimer: func.TimerRequest, signalRMessages: func.Out[str]) ->None: globaletagglobalstart_countheaders= {'User-Agent': 'serverless', 'If-None-Match': etag} res=requests.get('https://api.github.com/repos/azure/azure-signalr', headers=headers) ifres.headers.get('ETag'): etag=res.headers.get('ETag') ifres.status_code==200: jres=res.json() start_count=jres['stargazers_count'] signalRMessages.set(json.dumps({ 'target': 'newMessage', 'arguments': [ 'Current star count of https://github.com/Azure/azure-signalr is: '+str(start_count) ] }))

::: zone-end

Create the index.html file

The client interface for this app is a web page. The index function reads HTML content from the content/index.html file.

  1. Create a folder called content in your project root folder.
  2. Create the file content/index.html.
  3. Copy the following content to the content/index.html file and save it:
<html><body><h1>Azure SignalR Serverless Sample</h1><divid="messages"></div><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.min.js"></script><script>letmessages=document.querySelector('#messages');constapiBaseUrl=window.location.origin;constconnection=newsignalR.HubConnectionBuilder().withUrl(apiBaseUrl+'/api').configureLogging(signalR.LogLevel.Information).build();connection.on('newMessage',(message)=>{document.getElementById("messages").innerHTML=message;});connection.start().catch(console.error);</script></body></html>

Add the SignalR Service connection string to the function app settings

The last step is to set the SignalR Service connection string in Azure Function app settings.

  1. In the Azure portal, go to the SignalR instance you deployed earlier.

  2. Select Keys to view the connection strings for the SignalR Service instance.

    :::image type="content" source="media/signalr-quickstart-azure-functions-javascript/signalr-quickstart-keys.png" alt-text="Screenshot of Azure SignalR service Keys page.":::

  3. Copy the primary connection string, and execute the command:

    func settings add AzureSignalRConnectionString "<signalr-connection-string>"

Run the Azure Function app locally

Start the Azurite storage emulator:

azurite 

Run the Azure Function app in the local environment:

func start

Note

If you see an errors showing read errors on the blob storage, ensure the 'AzureWebJobsStorage' setting in the local.settings.json file is set to UseDevelopmentStorage=true.

After the Azure Function is running locally, go to http://localhost:7071/api/index. The page displays the current star count for the GitHub Azure/azure-signalr repository. When you star or unstar the repository in GitHub, you'll see the refreshed count every few seconds.

[!INCLUDE Cleanup]

Having issues? Try the troubleshooting guide or let us know.

Next steps

In this quickstart, you built and ran a real-time serverless application in local. Next, learn more about how to use bi-directional communicating between clients and Azure Function with SignalR Service.

[!div class="nextstepaction"] SignalR Service bindings for Azure Functions

[!div class="nextstepaction"] Bi-directional communicating in Serverless

[!div class="nextstepaction"] Deploy Azure Functions with VS Code

close