Skip to content
This repository was archived by the owner on Apr 13, 2026. It is now read-only.

Commit cfcbaa2

Browse files
committed
Handle Slack event errors
1 parent dc6508e commit cfcbaa2

2 files changed

Lines changed: 86 additions & 70 deletions

File tree

installer/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ services:
8282
slackbot:
8383
build: ./slackbot
8484
container_name: slackbot
85-
restart: no
86-
# set restart to unless-stopped if you intend to run the slackbot continuously
85+
restart: unless-stopped
86+
# set restart to no if you want to manually control the slackbot
8787
environment:
8888
SLACK_BOT_TOKEN: ${SLACK_BOT_TOKEN:-}
8989
SLACK_APP_TOKEN: ${SLACK_APP_TOKEN:-}

installer/slackbot/slack_bot.py

Lines changed: 84 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -308,78 +308,94 @@ def handle_help(user, thread_ts=None, channel=None):
308308

309309
# --- Event Processing Logic ---
310310
def process_events(client: SocketModeClient, req: SocketModeRequest):
311-
if req.type != "events_api":
312-
return
313-
314-
client.send_socket_mode_response(SocketModeResponse(envelope_id=req.envelope_id))
315-
event = req.payload.get("event", {})
316-
if event.get("type") != "message" or event.get("subtype") is not None:
317-
return
318-
319-
# Get channel type - check if it's a DM or the default channel
320-
channel = event.get("channel")
321-
channel_type = event.get("channel_type")
322-
323-
# Allow messages from default channel or DMs (im = direct message)
324-
is_dm = channel_type == "im"
325-
is_default_channel = channel == DEFAULT_CHANNEL
326-
327-
if not (is_dm or is_default_channel):
328-
return
329-
330-
msg_ts = event.get("ts")
331-
if msg_ts in processed_messages:
332-
print(f"Skipping already processed message: {msg_ts}")
333-
return
334-
335-
processed_messages.add(msg_ts)
336-
if len(processed_messages) > 1000:
337-
oldest_ts = sorted(processed_messages)[0]
338-
processed_messages.remove(oldest_ts)
339-
340-
user = event.get("user")
341-
bot_user_id = os.environ.get("SLACK_BOT_USER_ID", "U08P8KS8K25")
342-
if user == bot_user_id:
343-
print(f"Skipping message from bot itself ({bot_user_id}).")
344-
return
345-
346-
text = event.get("text", "").strip()
347-
if not text.startswith("!"):
348-
return
349-
350-
command_full = text[1:]
351-
command_parts = command_full.split()
352-
main_command = command_parts[0] if command_parts else ""
311+
try:
312+
if req.type != "events_api":
313+
return
353314

354-
print(
355-
f"Received command: '{command_full}' from user {user} "
356-
f"in {'DM' if is_dm else f'channel {channel}'}"
357-
)
315+
client.send_socket_mode_response(SocketModeResponse(envelope_id=req.envelope_id))
316+
event = req.payload.get("event", {})
317+
if event.get("type") != "message" or event.get("subtype") is not None:
318+
return
358319

359-
# Get thread_ts - use the message timestamp to create/reply to thread
360-
# For DMs, thread_ts is the same as msg_ts
361-
thread_ts = event.get("thread_ts") or msg_ts
362-
363-
# For DM responses, use the DM channel; otherwise use DEFAULT_CHANNEL
364-
response_channel = channel if is_dm else DEFAULT_CHANNEL
365-
366-
if main_command == "location":
367-
handle_location(user, thread_ts, response_channel)
368-
elif main_command == "testimage":
369-
handle_testimage(user, thread_ts, response_channel)
370-
elif main_command == "agent":
371-
handle_agent(user, command_full, thread_ts, timeout=120, channel=response_channel)
372-
elif main_command == "agent-debug":
373-
handle_agent(user, command_full, thread_ts, timeout=1200, channel=response_channel)
374-
elif main_command == "help":
375-
handle_help(user, thread_ts, response_channel)
376-
else:
377-
send_slack_message(
378-
response_channel,
379-
text=f"❓ <@{user}> Unknown command: `{text}`. Try `!help`.",
380-
thread_ts=thread_ts,
320+
# Get channel type - check if it's a DM or the default channel
321+
channel = event.get("channel")
322+
channel_type = event.get("channel_type")
323+
324+
# Allow messages from default channel or DMs (im = direct message)
325+
is_dm = channel_type == "im"
326+
is_default_channel = channel == DEFAULT_CHANNEL
327+
328+
if not (is_dm or is_default_channel):
329+
return
330+
331+
msg_ts = event.get("ts")
332+
if msg_ts in processed_messages:
333+
print(f"Skipping already processed message: {msg_ts}")
334+
return
335+
336+
processed_messages.add(msg_ts)
337+
if len(processed_messages) > 1000:
338+
oldest_ts = sorted(processed_messages)[0]
339+
processed_messages.remove(oldest_ts)
340+
341+
user = event.get("user")
342+
bot_user_id = os.environ.get("SLACK_BOT_USER_ID", "U08P8KS8K25")
343+
if user == bot_user_id:
344+
print(f"Skipping message from bot itself ({bot_user_id}).")
345+
return
346+
347+
text = event.get("text", "").strip()
348+
if not text.startswith("!"):
349+
return
350+
351+
command_full = text[1:]
352+
command_parts = command_full.split()
353+
main_command = command_parts[0] if command_parts else ""
354+
355+
print(
356+
f"Received command: '{command_full}' from user {user} "
357+
f"in {'DM' if is_dm else f'channel {channel}'}"
381358
)
382359

360+
# Get thread_ts - use the message timestamp to create/reply to thread
361+
# For DMs, thread_ts is the same as msg_ts
362+
thread_ts = event.get("thread_ts") or msg_ts
363+
364+
# For DM responses, use the DM channel; otherwise use DEFAULT_CHANNEL
365+
response_channel = channel if is_dm else DEFAULT_CHANNEL
366+
367+
if main_command == "location":
368+
handle_location(user, thread_ts, response_channel)
369+
elif main_command == "testimage":
370+
handle_testimage(user, thread_ts, response_channel)
371+
elif main_command == "agent":
372+
handle_agent(user, command_full, thread_ts, timeout=120, channel=response_channel)
373+
elif main_command == "agent-debug":
374+
handle_agent(user, command_full, thread_ts, timeout=1200, channel=response_channel)
375+
elif main_command == "help":
376+
handle_help(user, thread_ts, response_channel)
377+
else:
378+
send_slack_message(
379+
response_channel,
380+
text=f"❓ <@{user}> Unknown command: `{text}`. Try `!help`.",
381+
thread_ts=thread_ts,
382+
)
383+
except Exception as e:
384+
import traceback
385+
print(f"❌ Error processing event: {e}")
386+
traceback.print_exc()
387+
try:
388+
# Try to notify the user about the error
389+
if 'user' in locals() and 'response_channel' in locals():
390+
send_slack_message(
391+
response_channel,
392+
text=f"❌ <@{user}> An error occurred while processing your command. Please try again later.",
393+
thread_ts=locals().get('thread_ts')
394+
)
395+
except:
396+
# If even error notification fails, just log it
397+
print("Failed to send error notification to Slack")
398+
383399

384400
# --- Main Execution ---
385401
if __name__ == "__main__":

0 commit comments

Comments
 (0)