Slack Bolt force close modal on AWS Lambda

Viewed 49

I have a python app built on Slack's Bolt framework and deployed on AWS Lambda.

The flow is as such:

  1. A user triggers a global shortcut which opens a modal
  2. The modal has a small form where the user fills it and clicks submit.
  3. The request is sent to AWS API gateway where it is then sent to my AWS Lambda
  4. The lambda authenticates the user to Okta and invokes another lambda where the main logic is stored
  5. When the lambda is invoked, the Bolt app's work is done.

The issue here is that after submission of a form, Slack demands that an acknowledgement is sent within 3 seconds.

I don't think my app is meeting this requirement because of the Okta authentication. Because of that, an error message is showing after submission and the form is not closing:

slack-modal

This message is showing even though the request is successfull (It is showing because i am not meeting the 3 seconds requirements)

I want the modal to close even if there are errors.

Below is my python code:

main.py

app = App(
    process_before_response=True,
    raise_error_for_unhandled_request=True
)

def main(event, context):

# * Log to cloudwatch
logging.info(f"Main function started with event:\n {event}")

# * Create a slack handler
slack_handler = SlackRequestHandler(app=app)

# * Return the slack handler
return slack_handler.handle(event, context)

After the main is executed, it goes to a middleware where i verify whether the token is valid:

@app.use
def middleware_verifications(payload, next):
    
    # * Log to Cloudwatch
    logging.info(f"Middleware `middleware_verifications` running with payload:\n {payload}")

    # * Get the request type
    type = payload["type"].lower() if 'type' in payload else "command"

    # * Verify if this is a modal
    # * Do not do anything if request is a modal
    if type != "modal":

        # * Verify if the verification token matches
        if not (TOKEN == payload['token']):
            raise BoltError(f'Error while verifying the slack token')

    # * Goes to the next middleware
    next()

The view_submission is then sent to the function below:

# * View submissions goes here * #

@app.view("patching_scheduler_submit") @authenticate([TG.IT_PLATFORM.value]) def view_patching_scheduler(ack, body, client, view):

# * Log event to cloudwatch
logging.info(f"View patching scheduler body: {body}")

# * Acknowledge request
ack(
    {
        "response_action": "clear"
    }
)

# * Get the user id
user = body["user"]

# *** Extract input values
patching_type = view['state']['values']['ptype']['multi_static_select-action']['selected_option']['value']
patching_start_date = view['state']['values']['pstartdate']['datepicker-action']['selected_date']
patching_end_date = view['state']['values']['penddate']['datepicker-action']['selected_date']  
patching_start_time = view['state']['values']['pstarttime']['timepicker-action']['selected_time']  
patching_end_time = view['state']['values']['pendtime']['timepicker-action']['selected_time']  

# * Log to cloudwatch
logging.info(f"patching_type: {patching_type}")
logging.info(f"patching_start_date: {patching_start_date}")
logging.info(f"patching_end_date: {patching_end_date}")
logging.info(f"patching_start_time: {patching_start_time}")
logging.info(f"patching_end_time: {patching_end_time}")

# * Invoke the lambda integration
PatchingScheduler(
    username=user['username'],
    patching_type=patching_type,
    patching_start_date=patching_start_date,
    patching_end_date=patching_end_date,
    patching_start_time=patching_start_time,
    patching_end_time=patching_end_time
).call_integration()

# * Send a message to the user
client.chat_postMessage(channel=user["id"], text="Patching scheduler in progress.")

returnobject={
    "statusCode": 200,
    "headers": {
        "Content-Type": "application/json"
    },
    "body": "",
    "response_action": "clear"
}
return returnobject

The decorator @authenticate([TG.IT_PLATFORM.value]) is where the code takes time because it has to check the user against the Okta API which takes more than 3 seconds.

I also tried to remove the decorator and use the authenticate inside the function after the ack() but it still gave me the error on the modal:

@app.view("patching_scheduler_submit")
def view_patching_scheduler(ack, body, client, view):

    # * Log event to cloudwatch
    logging.info(f"View patching scheduler body: {body}")

    # * Acknowledge request
    ack(
        {
            "response_action": "clear"
        }
    )

    # * Get the user id
    user = body["user"]

    # Authenticate
    authenticate([TG.IT_PLATFORM.value])

The modal doesn't close. Can someone help me out ?

1 Answers

Have you set the processBeforeResponse option to true? It is recommended for FaaS

enter image description here

Related