Cached data can sometimes be corrupted, which can lead to performance problems. It can also prevent applications and websites from loading the latest version of their content. That’s why clearing cache is a must, not only does it resolve these issues, it also clears up space. Clearing cache is also a way to protect privacy since cache can hold sensitive information.
About the task
Currently, when purging the cache for both TD Portal and TD Main Site, 4 slack commands have to be used:
For TD Portal:
- /clear-w3 portal
- /clear-fastcgi portal
For TD Main Site:
- /clear-wprocket main
- /clear-fastcgi main
Using these individual commands can be quite a hassle and can also be time-consuming. To resolve this problem, a new slack command has been created (/clear-cache) that takes in a parameter, which can be either portal (For TD Portal) or main (For TD Main Site).
- /clear-cache portal
-
- Clears cache for W3, then Fast-CGI.
-
- /clear-cache main
-
- Clears cache for WP-Rocket, then Fast-CGI.
-
Architecture Diagram
Implementation steps
Creating Slack Bot
If you already have a Slack Application, you may skip this step.
- Go to Slack API, then click Create New App.
- Select From Scratch and provide the necessary details:
-
- App Name:
Your own app name
- Workspace:
The Slack Workspace where you will put the bot in
- App Name:
-
Creating the SSM Documents
Before we create the Lambda functions, we must first create the SSM Documents that will be accessed by the Lambda functions. We will be creating 3 documents: TD-PurgeW3, TD-PurgeFastCGI, and TD-PurgeWPRocket.
- Go to AWS Management Console, then search for AWS Systems Manager.
- Go to Shared Resources > Documents
- Click Create document > Command or Session (After inputting the details on each Document, at the bottom right side of the screen: Click Create document)
-
- First Document:
-
- Name: TD-PurgeW3
- Document Type: Command
- Content: JSON, then input the following:
{ "schemaVersion": "2.2", "description": "Purges NGINX FastCGI cache", "parameters": { "slackHook": { "type": "String", "description": "(Required) Slack Web hook." }, "requesterName": { "type": "String", "description": "(Required) Slack user who purges the cache." }, "targetInstance": { "type": "String", "description": "(Required) Portal or Main site" } }, "mainSteps": [ { "action": "aws:runShellScript", "name": "runShellScript", "inputs": { "runCommand": [ "#!/bin/bash", "hook='{{ slackHook }}'", "sudo -u ubuntu -i -- wp w3-total-cache flush all --path=[Put here working directory]", "#Notify Slack Channel", "curl -H \"Content-type: application/json\" -d '{\"text\": \"{{ targetInstance }}: {{ requesterName }} cleared W3 Total Cache\"}' -X POST $hook" ] } } ] }
-
- Second Document:
-
- Name: TD-PurgeFastCGI
- Document Type: Command
- Content: JSON, then input the following:
{ "schemaVersion": "2.2", "description": "Purges NGINX FastCGI cache", "parameters": { "slackHook": { "type": "String", "description": "(Required) Slack Web hook." }, "requesterName": { "type": "String", "description": "(Required) Slack user who purges the cache." }, "targetInstance": { "type": "String", "description": "(Required) Portal or Main site" } }, "mainSteps": [ { "action": "aws:runShellScript", "name": "runShellScript", "inputs": { "runCommand": [ "#!/bin/bash", "hook='{{ slackHook }}'", "Working_Directory=\[Put here working directory]", "if [[ -d \"$Working_Directory\" ]]; then", "dir_size=$(sudo du -sh $Working_Directory | awk '{print $1}')", "echo \"Removing cache...\"", "sudo rm -rf $Working_Directory/*", "#Notify Slack Channel", "curl -H \"Content-type: application/json\" -d '{\"text\": \"{{ targetInstance }}: {{ requesterName }} cleared '$dir_size' of cache\"}' -X POST $hook", "else", "echo \"Cache is empty\"", "fi" ] } } ] }
-
- Third Document:
-
- Name: TD-PurgeWPRocket
- Document Type: Command
- Content: JSON, then input the following:
{ "schemaVersion": "2.2", "description": "Purges WP Rocket cache", "parameters": { "slackHook": { "type": "String", "description": "(Required) Slack Web hook." }, "requesterName": { "type": "String", "description": "(Required) Slack user who purges the cache." }, "targetInstance": { "type": "String", "description": "(Required) Portal or Main site" } }, "mainSteps": [ { "action": "aws:runShellScript", "name": "runShellScript", "inputs": { "runCommand": [ "#!/bin/bash", "hook='{{ slackHook }}'", "Working_Directory=\[Put here working directory]", "if [[ -d \"$Working_Directory\" ]]; then", "dir_size=$(sudo du -sh $Working_Directory | awk '{print $1}')", "echo \"Removing cache...\"", "sudo rm -rf $Working_Directory/*", "#Notify Slack Channel", "curl -H \"Content-type: application/json\" -d '{\"text\": \"{{ targetInstance }}: {{ requesterName }} cleared '$dir_size' of WP Rocket cache\"}' -X POST $hook", "else", "echo \"Cache is empty\"", "fi" ] } } ] }
-
- First Document:
-
Setting up Lambda Functions
We will be creating 2 Lambda functions. The first one (TD-ClearAllCache) accepts a synchronous call from Slack and then returns an acknowledgment response to Slack. The second one (TD-ClearCacheLogic) accepts an asynchronous call from the first lambda function and then sends a response to Slack through the use of the ssm.send_command()
.
- On the AWS Management Console, search for Lambda.
- Click the Create function, then supply the necessary information:
-
- Function name: TD-ClearAllCache
- Runtime: Python 3.11
- Existing role: td-invoke-purge-fastcgi-cache-role
-
- Go to the Configuration tab and activate the Function URL (This is only for TD-ClearAllCache).
-
- Auth type: None
-
- Create another Lambda function with this information:
-
- Function name: TD-ClearCacheLogic
- Runtime: Python 3.11
- Existing role: td-invoke-purge-fastcgi-cache-role
-
- For both Lambda functions, go to Configuration > Environment variables:
-
- For TD-ClearAllCache:
- SIGNING_KEY:
You can get this from your Slack Application
- SLACK_HOOK:
Webhook URL from Slack
- SLACK_CHANNEL:
Slack channel where you will test/use the command
- SIGNING_KEY:
- For TD-ClearCacheLogic:
- PORTAL_INSTANCE_ID:
Instance ID
- MAIN_INSTANCE_ID:
Instance ID
- SSM_PURGE_FASTCGI:
TD-PurgeFastCGI
- SSM_PURGE_W3:
TD-Purge-W3
- SSM_PURGE_WPRocket:
TD-PurgeWPRocket
- PORTAL_INSTANCE_ID:
- For TD-ClearAllCache:
-
- For both Lambda functions, go to Configuration > General configuration:
-
- For TD-ClearAllCache: Change Timeout to 10 sec
- For TD-ClearCacheLogic: Change Timeout to 30 sec
-
- Use the following code for the respective Lambda functions:
-
- For TD-ClearAllCache:
import json import boto3 import base64 import os import hashlib import hmac lambda_client = boto3.client('lambda') #Set up constants SLACK_CHANNEL = os.environ["SLACK_CHANNEL"] SIGNING_KEY = os.environ["SIGNING_KEY"] SLACK_HOOK = os.environ["SLACK_HOOK"] def lambda_handler(event, context): #Parse event data slack_signature = event['headers']["x-slack-signature"] slack_timestamp = event['headers']['x-slack-request-timestamp'] slack_payload = event['body'] payload = parse_slack_payload(slack_payload) from_channel = payload["channel_name"] #Check if request originates from valid source from_valid_source = verify_source(signing_key=SIGNING_KEY.encode('utf-8'), timestamp=slack_timestamp, body=base64.b64decode(slack_payload).decode('utf-8'), slack_signature=slack_signature, from_channel=from_channel ) if from_valid_source: new_payload = { 'body': { 'target_instance': payload['text'], 'requester': payload["user_name"], 'hook': SLACK_HOOK } } try: lambda_client.invoke(FunctionName='TD-ClearCacheLogic', InvocationType='Event', Payload=json.dumps(new_payload) ) return f'Request Authorized \nRequest Id: {context.aws_request_id}' except Exception as e: return f'{e}' else: return "You're not authorized to do this operation" def parse_slack_payload(data): # decode the data using the b64decode function decoded_data_raw = base64.b64decode(data).decode('utf-8').split('&') decoded_data_formatted={key:value for key, value in [i.split("=") for i in decoded_data_raw]} return decoded_data_formatted def verify_source(signing_key, timestamp, body, slack_signature, from_channel): basetring = f'v0:{timestamp}:{body}' hmac_digest = hmac.new(key=signing_key, msg=basetring.encode('utf-8'), digestmod=hashlib.sha256).hexdigest() if hmac.compare_digest(slack_signature, f'v0={hmac_digest}') and SLACK_CHANNEL == from_channel: return True
- For TD-ClearCacheLogic:
import boto3 from botocore.config import Config import os import time #Set up constants PORTAL_INSTANCE_ID = os.environ["PORTAL_INSTANCE_ID"] MAIN_INSTANCE_ID = os.environ["MAIN_INSTANCE_ID"] SSM_PURGE_FASTCGI = os.environ["SSM_PURGE_FASTCGI"] SSM_PURGE_W3 = os.environ["SSM_PURGE_W3"] SSM_PURGE_WPRocket = os.environ["SSM_PURGE_WPRocket"] def lambda_handler(event, context): payload = event["body"] hook = payload['hook'] requester = payload['requester'] target_instance = payload['target_instance'] purge_cache(hook, requester, target_instance) return def purge_cache(hook, requester, target_instance): target_instances = { 'portal': { 'instance_id': PORTAL_INSTANCE_ID, 'region': [put here the region where your instance is located e.g 'us-east-1'] }, 'main': { 'instance_id': MAIN_INSTANCE_ID, 'region': [put here the region where your instance is located e.g 'us-east-1'] } } instance_ssm_documents = { 'portal':{ 'w3': SSM_PURGE_W3, 'fastcgi': SSM_PURGE_FASTCGI }, 'main': { 'wprocket': SSM_PURGE_WPRocket, 'fastcgi': SSM_PURGE_FASTCGI } } for target_document in instance_ssm_documents[target_instance].values(): target_instance_id = target_instances[target_instance]['instance_id'] target_region = target_instances[target_instance]['region'] print(target_instance_id, target_region, target_document) ssm = boto3.client('ssm', config=Config(region_name = target_region)) response = ssm.send_command( InstanceIds=[ target_instance_id, ], DocumentName=target_document, Parameters={ 'slackHook': [hook], 'requesterName': [requester], 'targetInstance': [ target_instance.upper() ] }, TimeoutSeconds=30 ) print(response) time.sleep(6)
- For TD-ClearAllCache:
-
Connecting the Slack Slash Command to the Lambda function using the Function URL
- Go to TD-ClearAllCache and copy the Function URL.
- Go to your Slack Application, then go to Slash Commands.
- Click Create New Command, then input the necessary details:
-
- Command:
/clear-cache
- Request URL:
The Function URL goes here
- Short Description:
Put here what your slash command is supposed to do
- Usage Hint:
Here you can put the parameters that the command needs in order to work
- Command:
-
- Double-check the Preview of Autocomplete Entry, then click Save.
Using the Slash Command
- Go to the channel where you will test the Slash Command.
- Type
/clear-cache portal | main
-
[portal | main]
are the parameters to choose from. Whether to clear TD Portal or TD Main Site.
-
- This should be the output for
/clear-cache portal
:
- This should be the output for
/clear-cache main
:
Rollback Plan
Deleting Slack App:
- Go to Slack API > Your Apps > then click the name of your app in App Name
-
Scroll down, then click Delete App
Deleting Lambda Functions:
- Go to either TD-ClearAllCache or TD-ClearCacheLogic
- Click the Actions dropdown box, then click the Delete function
- Then, repeat the steps for the other function.
AWS, Azure, and GCP Certifications are consistently among the top-paying IT certifications in the world, considering that most companies have now shifted to the cloud. Earn over $150,000 per year with an AWS, Azure, or GCP certification!
Follow us on LinkedIn, YouTube, Facebook, or join our Slack study group. More importantly, answer as many practice exams as you can to help increase your chances of passing your certification exams on your first try!
View Our AWS, Azure, and GCP Exam Reviewers Check out our FREE courses