title: AWS Lambda & MySQL Connection Handling
body: <p>I am currently using AWS Lambda (Python 3.6) to talk to a MySQL database. I also have Slack commands triggering the queries to the database. On occasion, I have noticed that I can change things directly through MySQL Workbench and then trigger a query through Slack which returns old values. I currently connect to MySQL outside of the python handler like this:</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>The MySQL connection is done outside of any definition at the very top of my program. When Slack sends a command, I call another definition that then queries MySQL. This works okay sometimes, but other times can send my old data that has not updated. The whole layout is like this:</p>
  
  <p>imports
  SQL connections
  SQL query definitions
  handler definition</p>
  
  <p>I tried moving the MySQL connection portion inside of the handler, but then the SQL query definitions do not recognize my cursor (out of scope, I guess).</p>
  
  <p>So my question is, how do I handle this MySQL connection? Is it best to keep the MySQL connection outside of any definitions? Should I open and close the connection each time? Why is my data stale? Will Lambda ALWAYS run the entire routine or can it try to split the load between servers (I swear I read somewhere that I cannot rely on Lambda to always read my entire routine; sometimes it just reads the handler)?</p>
  
  <p>I'm pretty new to all this, so any suggestions are much appreciated. Thanks!</p>
  
  <p>Rest of the code if it helps:</p>
  
  <pre><code>################################################################################################################################################################################################################
  # 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"
  ################################################################################################################################################################################################################
  </code></pre>