【问题标题】:AWS Lambda & MySQL Connection HandlingAWS Lambda 和 MySQL 连接处理
【发布时间】:2018-06-20 22:20:38
【问题描述】:

我目前正在使用 AWS Lambda (Python 3.6) 与 MySQL 数据库通信。我也有 Slack 命令触发对数据库的查询。有时,我注意到我可以直接通过 MySQL Workbench 进行更改,然后通过 Slack 触发返回旧值的查询。我目前在 python 处理程序之外连接到 MySQL,如下所示:

BOT_TOKEN   = os.environ["BOT_TOKEN"]
ASSET_TABLE = os.environ["ASSET_TABLE"]
REGION_NAME = os.getenv('REGION_NAME', 'us-east-2')
DB_NAME     = os.environ["DB_NAME"]
DB_PASSWORD = os.environ["DB_PASSWORD"]
DB_DATABASE = os.environ["DB_DATABASE"]
RDS_HOST    = os.environ["RDS_HOST"]
port        = os.environ["port"]

try:
    conn = pymysql.connect(RDS_HOST, user=DB_NAME, passwd=DB_PASSWORD, db=DB_DATABASE, connect_timeout=5, cursorclass=pymysql.cursors.DictCursor)
    cursor = conn.cursor()
except:
    sys.exit()

MySQL 连接是在我的程序顶部的任何定义之外完成的。当 Slack 发送命令时,我调用另一个定义,然后查询 MySQL。这有时可以正常工作,但其他时候可以发送我尚未更新的旧数据。整个布局是这样的:

进口 SQL 连接 SQL 查询定义 处理程序定义

我尝试在处理程序内移动 MySQL 连接部分,但是 SQL 查询定义无法识别我的光标(我猜超出了范围)。

所以我的问题是,我该如何处理这个 MySQL 连接?是否最好将 MySQL 连接保持在任何定义之外?我应该每次打开和关闭连接吗?为什么我的数据过时了? Lambda 是否总是运行整个例程,或者它是否可以尝试在服务器之间分配负载(我发誓我在某处读到我不能依赖 Lambda 始终读取我的整个例程;有时它只是读取处理程序)?

我对这一切都很陌生,因此非常感谢任何建议。谢谢!

如果有帮助,其余代码:

################################################################################################################################################################################################################
# Slack Lambda handler.
################################################################################################################################################################################################################

################################################################################################################################################################################################################
# IMPORTS
###############
import sys
import os
import pymysql
import urllib
import math
################################################################################################################################################################################################################


################################################################################################################################################################################################################
# Grab data from AWS environment.
###############
BOT_TOKEN   = os.environ["BOT_TOKEN"]
ASSET_TABLE = os.environ["ASSET_TABLE"]
REGION_NAME = os.getenv('REGION_NAME', 'us-east-2')
DB_NAME     = os.environ["DB_NAME"]
DB_PASSWORD = os.environ["DB_PASSWORD"]
DB_DATABASE = os.environ["DB_DATABASE"]
RDS_HOST    = os.environ["RDS_HOST"]
port        = os.environ["port"]
################################################################################################################################################################################################################


################################################################################################################################################################################################################
# Attempt SQL connection.
###############
try:
    conn = pymysql.connect(RDS_HOST, user=DB_NAME, passwd=DB_PASSWORD, db=DB_DATABASE, connect_timeout=5, cursorclass=pymysql.cursors.DictCursor)
    cursor = conn.cursor()
except:
    sys.exit()
################################################################################################################################################################################################################

# Define the URL of the targeted Slack API resource.
SLACK_URL = "https://slack.com/api/chat.postMessage"

################################################################################################################################################################################################################
# Function Definitions.
###############

def get_userExistance(user):
    statement = f"SELECT 1 FROM slackDB.users WHERE userID LIKE '%{user}%' LIMIT 1"
    cursor.execute(statement, args=None)
    userExists  =  cursor.fetchone()
    return userExists

def set_User(user):
    statement = f"INSERT INTO `slackDB`.`users` (`userID`) VALUES ('{user}');"
    cursor.execute(statement, args=None)
    conn.commit()
    return

################################################################################################################################################################################################################

################################################################################################################################################################################################################
# Slack command interactions.
###############
def lambda_handler(data, context):

    # Slack challenge answer.
    if "challenge" in data:
        return data["challenge"]

    # Grab the Slack channel data.
    slack_event    = data['event']
    slack_userID   = slack_event['user']
    slack_text     = slack_event['text']
    channel_id     = slack_event['channel']
    slack_reply    = ""

    # Check sql connection.
    try:
        conn = pymysql.connect(RDS_HOST, user=DB_NAME, passwd=DB_PASSWORD, db=DB_DATABASE, connect_timeout=5, cursorclass=pymysql.cursors.DictCursor)
        cursor = conn.cursor()
    except pymysql.OperationalError:
        connected = 0
    else:
        connected = 1

    # Ignore bot messages.
    if "bot_id" in slack_event:
        slack_reply = ""
    else:
        # Start data sift.
        if slack_text.startswith("!addme"):
            if get_userExistance(slack_userID):
                slack_reply = f"User {slack_userID} already exists"
            else:
                slack_reply = f"Adding user {slack_userID}"
                set_user(slack_userID)

        # We need to send back three pieces of information:
        data = urllib.parse.urlencode(
            (
                ("token", BOT_TOKEN),
                ("channel", channel_id),
                ("text", slack_reply)
            )
        )
        data = data.encode("ascii")

        # Construct the HTTP request that will be sent to the Slack API.
        request = urllib.request.Request(
            SLACK_URL, 
            data=data, 
            method="POST"
        )
        # Add a header mentioning that the text is URL-encoded.
        request.add_header(
            "Content-Type", 
            "application/x-www-form-urlencoded"
        )

        # Fire off the request!
        urllib.request.urlopen(request).read()

    # Everything went fine.
    return "200 OK"
################################################################################################################################################################################################################

【问题讨论】:

    标签: python mysql python-3.x amazon-web-services


    【解决方案1】:

    lambda 处理程序之外的所有代码每个容器仅运行一次。每次调用 lambda 时都会运行处理程序中的所有代码。

    一个 lambda 容器可持续 10 到 30 分钟,具体取决于使用情况。新的 lambda 调用可能会或可能不会在已运行的容器上运行。

    您可能在连接已超时的 5 分钟前的容器中调用 lambda。

    【讨论】:

    • 所以最好的做法是在处理程序中运行 MySQL 连接并以某种方式将其传递给我的其他定义?或者两个检查处理程序内部的 MySQL 连接是否打开,如果没有,重新连接?
    • 对pymysql不太熟悉,但在类似的情况下,我会在处理程序代码的顶部检查连接,如果丢失则重新建立连接。您可能必须关闭并打开光标才能使其正常工作。
    • 我添加了一个 try/except (更新代码以显示位置),但我仍然有一个问题,我可以更新 MySQL Workbench 中的值并且在查询中看不到它。我可以保存 Lambda(猜测容器重新启动)并且新值被正确提取。我也可以让 slack 使用一个集合查询,这似乎会更新。但是为什么有时候数据和数据库不匹配呢?
    • 没关系,我开始阅读一些类似的问题,似乎在我的连接代码中添加 autocommit=True 解决了这个问题。感谢您在其他方面的帮助!
    猜你喜欢
    • 2021-10-13
    • 1970-01-01
    • 2018-05-13
    • 2018-01-13
    • 2021-04-19
    • 2020-05-31
    • 2019-09-01
    • 2020-05-19
    • 1970-01-01
    相关资源
    最近更新 更多