[Python] Can't get my Python bot to work in Azure Web App Services alongside Flask

Discussão em 'Python' iniciado por Stack, Março 7, 2025.

  1. Stack

    Stack Membro Participativo

    What I have


    I have a Python bot that used to work on my VPS and I want to move it to Azure Web App Service.

    (To avoid confusion: I'm talking about the Azure Web App Service intended for websites, not Azure Bot Service. The reason is I want to keep my current code structure that is not adjusted to a specific platform, so I can move it back to my VPS or another provider at any point, and from what I read on Azure Bot Service, it sounds like a kind of vendor lock-in.)

    When I deploy my existing (original) bot to my Azure Web App it starts fine, but shuts down shortly.

    What is the problem


    Azure expects my code to serve WSGI-compatible HTTP requests. Because my original code is just a bot that runs in a loop and doesn't serve anything, after ~250 seconds Azure shuts down the app:


    Container my-bot didn't respond to HTTP pings on port: 8000, failing site start. See container logs for debugging
    ​

    I understand the solution is to use a framework such as Flask

    What I tried


    I tried to run Flask alongside my loop. But whichever runs first apparently hijacks the process, and blocks the other one, so it never runs.

    To fix that I tried all kinds of combinations of multiprocessing, asyncio and threading. Here's the latest version I ended up with:

    import threading
    from flask import Flask, jsonify
    import logging
    import sys
    import asyncio
    import datetime
    import os
    import telegram
    import time


    logging.basicConfig(level=logging.INFO, handlers=[logging.StreamHandler(sys.stdout)])


    class Bot:
    def __init__(self):
    self.bot_token = os.getenv('TOKEN')
    self.chat_id = os.getenv('CHAT_ID')
    self.telegram_bot = telegram.Bot(token=self.bot_token)
    self.sleep = os.getenv('SLEEP') # set to 60

    def run(self):
    while True:
    current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    message = f"It's {current_time} o'clock!\n\nSent from " + __file__
    self.send_notification(message)
    time.sleep(int(self.sleep))

    def send_notification(self, message):

    async def send_message():
    await self.telegram_bot.send_message(chat_id=self.chat_id, text=message)

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(send_message())


    bot = Bot()
    app = Flask(__name__)


    # Simple endpoint that responds to Azure ping
    @app.route('/')
    def home():
    return jsonify(
    hello='world',
    now=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    ), 200


    if __name__ == '__main__':
    bot_thread = threading.Thread(target=bot.run)
    bot_thread.daemon = True # ChatGPT says this ensures the bot thread will stop when the main thread exits
    bot_thread.start()
    app.run(host=os.getenv("HTTP_HOST", "0.0.0.0"), port=int(os.getenv("HTTP_PORT")))


    This works fine on my local: it both 1. serves HTTP requests and 2. sends out a message every 60 seconds.

    Azure


    The above runs and serves HTTP requests, but the bot does not work. No errors in logs. Checked all logs under https://.scm.azurewebsites.net/api/logs/docker

    This is a Linux Web App on their free tier.

    {
    "type": "Microsoft.Web/sites",
    "kind": "app,linux",
    "properties": {
    "state": "Running",
    "usageState": "Normal",
    "siteScopedCertificatesEnabled": false,
    "afdEnabled": false,
    "siteProperties": {
    "properties": [
    {
    "name": "LinuxFxVersion",
    "value": "PYTHON|3.13"
    },
    {
    "name": "WindowsFxVersion",
    "value": null
    }
    ],
    "appSettings": null
    },
    "availabilityState": "Normal",
    "csrs": [],
    "cers": null,
    "siteMode": null,
    "computeMode": null,
    "serverFarm": null,
    "reserved": true,
    "isXenon": false,
    "hyperV": false,
    "storageRecoveryDefaultState": "Running",
    "contentAvailabilityState": "Normal",
    "runtimeAvailabilityState": "Normal",
    "dnsConfiguration": {},
    "vnetRouteAllEnabled": false,
    "containerAllocationSubnet": null,
    "useContainerLocalhostBindings": null,
    "vnetImagePullEnabled": false,
    "vnetContentShareEnabled": false,
    "outboundVnetRouting": null,
    "siteConfig": {
    "numberOfWorkers": 1,
    "defaultDocuments": null,
    "netFrameworkVersion": null,
    "phpVersion": null,
    "pythonVersion": null,
    "nodeVersion": null,
    "powerShellVersion": null,
    "linuxFxVersion": "PYTHON|3.13",
    "windowsFxVersion": null,
    "windowsConfiguredStacks": null,
    "requestTracingEnabled": null,
    "remoteDebuggingEnabled": null,
    "remoteDebuggingVersion": null,
    "httpLoggingEnabled": null,
    "azureMonitorLogCategories": null,
    "acrUseManagedIdentityCreds": false,
    "acrUserManagedIdentityID": null,
    "logsDirectorySizeLimit": null,
    "detailedErrorLoggingEnabled": null,
    "publishingUsername": null,
    "publishingPassword": null,
    "appSettings": null,
    "metadata": null,
    "connectionStrings": null,
    "machineKey": null,
    "handlerMappings": null,
    "documentRoot": null,
    "scmType": null,
    "use32BitWorkerProcess": null,
    "webSocketsEnabled": null,
    "alwaysOn": false,
    "javaVersion": null,
    "javaContainer": null,
    "javaContainerVersion": null,
    "appCommandLine": null,
    "managedPipelineMode": null,
    "virtualApplications": null,
    "winAuthAdminState": null,
    "winAuthTenantState": null,
    "customAppPoolIdentityAdminState": null,
    "customAppPoolIdentityTenantState": null,
    "runtimeADUser": null,
    "runtimeADUserPassword": null,
    "loadBalancing": null,
    "routingRules": null,
    "experiments": null,
    "limits": null,
    "autoHealEnabled": null,
    "autoHealRules": null,
    "tracingOptions": null,
    "vnetName": null,
    "vnetRouteAllEnabled": null,
    "vnetPrivatePortsCount": null,
    "publicNetworkAccess": null,
    "cors": null,
    "push": null,
    "apiDefinition": null,
    "apiManagementConfig": null,
    "autoSwapSlotName": null,
    "localMySqlEnabled": null,
    "managedServiceIdentityId": null,
    "xManagedServiceIdentityId": null,
    "keyVaultReferenceIdentity": null,
    "ipSecurityRestrictions": null,
    "ipSecurityRestrictionsDefaultAction": null,
    "scmIpSecurityRestrictions": null,
    "scmIpSecurityRestrictionsDefaultAction": null,
    "scmIpSecurityRestrictionsUseMain": null,
    "http20Enabled": true,
    "minTlsVersion": null,
    "minTlsCipherSuite": null,
    "scmMinTlsCipherSuite": null,
    "supportedTlsCipherSuites": null,
    "scmSupportedTlsCipherSuites": null,
    "scmMinTlsVersion": null,
    "ftpsState": null,
    "preWarmedInstanceCount": null,
    "functionAppScaleLimit": 0,
    "elasticWebAppScaleLimit": null,
    "healthCheckPath": null,
    "fileChangeAuditEnabled": null,
    "functionsRuntimeScaleMonitoringEnabled": null,
    "minimumElasticInstanceCount": 1,
    "azureStorageAccounts": null,
    "http20ProxyFlag": null,
    "sitePort": null,
    "antivirusScanEnabled": null,
    "storageType": null,
    "sitePrivateLinkHostEnabled": null,
    "clusteringEnabled": false
    },
    "functionAppConfig": null,
    "daprConfig": null,
    "deploymentId": "<app>",
    "slotName": null,
    "trafficManagerHostNames": null,
    "sku": "Free",
    "scmSiteAlsoStopped": false,
    "targetSwapSlot": null,
    "hostingEnvironment": null,
    "hostingEnvironmentProfile": null,
    "clientAffinityEnabled": false,
    "clientAffinityProxyEnabled": false,
    "blockPathTraversal": false,
    "clientCertEnabled": false,
    "clientCertMode": "Required",
    "clientCertExclusionPaths": null,
    "hostNamesDisabled": false,
    "ipMode": "IPv4",
    "vnetBackupRestoreEnabled": false,
    "domainVerificationIdentifiers": null,
    "kind": "app,linux",
    "managedEnvironmentId": null,
    "workloadProfileName": null,
    "resourceConfig": null,
    "containerSize": 0,
    "dailyMemoryTimeQuota": 0,
    "suspendedTill": null,
    "siteDisabledReason": 0,
    "functionExecutionUnitsCache": null,
    "maxNumberOfWorkers": null,
    "cloningInfo": null,
    "hostingEnvironmentId": null,
    "slotSwapStatus": null,
    "httpsOnly": false,
    "endToEndEncryptionEnabled": false,
    "functionsRuntimeAdminIsolationEnabled": false,
    "redundancyMode": "None",
    "inProgressOperationId": null,
    "geoDistributions": null,
    "privateEndpointConnections": [],
    "publicNetworkAccess": "Enabled",
    "buildVersion": null,
    "targetBuildVersion": null,
    "migrationState": null,
    "eligibleLogCategories": "AppServiceAppLogs,AppServiceAuditLogs,AppServiceConsoleLogs,AppServiceHTTPLogs,AppServiceIPSecAuditLogs,AppServicePlatformLogs,ScanLogs,AppServiceAuthenticationLogs",
    "inFlightFeatures": [
    "SiteContainers"
    ],
    "storageAccountRequired": false,
    "virtualNetworkSubnetId": null,
    "keyVaultReferenceIdentity": "SystemAssigned",
    "autoGeneratedDomainNameLabelScope": null,
    "defaultHostNameScope": "Global",
    "privateLinkIdentifiers": null,
    "sshEnabled": true
    },
    "apiVersion": "2022-03-01"
    }

    Render.com


    In addition to Azure, I deployed the above as a "Web Service" on Render.com. It works fine, both serving HTTP and sending me a message every 60 seconds.

    How do I make the above work with Azure?

    Continue reading...

Compartilhe esta Página