Forums

Help diagnosing [Errno 5] return code 120

Here is the error message:

Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'> OSError: [Errno 5] Input/output error

2023-08-21 18:47:59 -- Completed task, took 4491.69 seconds, return code was 120.

Based on the looks of the error, I'm thinking this is an issue on PythonAnywhere's end rather than in our Python script itself. This script uses print() quite a bit, but inconsistently runs into this i/o error. Would appreciate some insight as to potential causes.

For context, the script ideally runs for a 58 minute duration (ends up closer to 59). The script runs on an hourly schedule, so there a 1-2 minute gap between runs. The run preceding the error was on pace, finishing in 59 minutes. So I don't think there should be any concurrency issues, but thought I'd mention it.

Happy to provide more info about the script if need be. Thanks for any help!

What is the code that is causing it?

The script is pretty long; without the error message referring to a line number or anything specific, it's hard to say which code is causing the issue. The script does try to print() some things to the log pretty early in its run, but none of these are present in the log for the runs that get this error.

The structure of the file is this:

imports <-- everything imported is used in various other scripts without issue
constant assignments
fn definitions
print('start') <-- *this does not show in the log when the error occurs*
logic + function calls

Here's the code in full:

#!/usr/bin/python3.6
# -*- coding: utf-8 -*-

import os
os.chdir('/home/livingspaces/attributeaudits/')


################################### UPDATE HERE AND DOWN  #####################################################################################################
import random, time
from SupportGeneral import timeStamp, getCurrentHour,getTodaysDate, listSortingFunction, sendEmailViaSendGrid
from SupportIntercom import checkIfAssigneeIsAdmin,getContactIdFromConversationObject, checkIfAdminIsActive, getAdminIdBasedOnName, getContactDict, getListOfChatsBasedOnInboxAndState, getListOfChatsBasedOnInboxAndStateAndLongestWaitingTime, getLastAutomatedGSFollowup, updateContactsWithoutEmailsButDoHaveMktEmails, getListOfChatsBasedOnInboxAndStateAndLastUpdatedTime, findChatsToCloseBasedOnSisterChats, closeOldConversationsWithNoGuestEmailFromInboxes, getAdminsandTeamMembersDicts, getListOfChatsBasedOnState, getDictOfConversation, assignConversationToAdmin, addNoteToConversation,addMessageToConversation, closeAConversation, openAConversation, snoozeAConversation, updateContactCustomAttribute,contactIsQuarantined,conversationIsQuarantined,getContactOwnerId
from SupportGoogle import getRecipientListFromGoogleSheets, updateScriptStatusInPythonMasterLogGoogleSheet,getIntercomAutomatedFollowupSettings
##################################################  CONSTANTS  ##########################################################

helperBotId = 3938197
gSGeneralInboxId =   4096911
gsScheduleRescheduleInboxId = 4219522
koreBotId = 999
quarantineInboxId = 5250862
eCommerceInboxId = 4103832
rtEligibleForGSChatsInboxId = 5126001
rtEligibleForAutoassignment = 4634354
rtGeneralInboxId = 4098304

bodyForCommentWhenSnoozedOneMonthInFuture = "Hi! Just reaching out to see if you might need any more assistance. Just reply to this email and I'll get back to you with any help you might need."
bodyForCommentFromGSWhenNoActionYetFromUs = "Sorry we haven't been able to get back to you sooner. Due to Covid19 and the impact on our call center operations, we have a significant backlog we are working through as quickly as possible. If you haven't had your issue resolved via phone or email yet, please reply to this email and we'll get back to you as soon as possible."
bodyForCommentFromChatGoesDeadAndNoGuestEmail = "We are going to close this conversation for now but when you do come back in the future, feel free to respond to this conversation and we can continue helping with any questions you might have."
bodyForCommentWhenNoGuestEmail = "We're sorry we missed your chat. If you need help in the future, please start a new chat and we'll reply as soon as possible."
commentTextForFinalFollow = "Hello. Just checking in one last time. You can still reply at any time and we'll get back to you as quickly as possible."
commentTextForFinalFollowupOld = "Hello. Just checking in one last time. I will be closing this conversation but you can stil reply at any time and we'll get back to you as quickly as possible."

##################################################  FUNCTIONS  ##########################################################

def pushInboxConversationsToApplicableAgents(inboxToProcess,inboxExclusionList,inboxNameToIdDict, teamMembers, admins):
  inboxIdExclusionList = []
  for inboxToExclude in inboxExclusionList:
    inboxIdExclusionList.append(inboxNameToIdDict[inboxToExclude])

  inboxIdToProcess = inboxNameToIdDict[inboxToProcess]
  currentTimestamp = int(time.time())
  lastUpdatedTimeThreshold = currentTimestamp - 60*60*72  #Only want to look at conversations updated within last 72 hours
  listOfChats = getListOfChatsBasedOnInboxAndStateAndLastUpdatedTime(inboxIdToProcess,"open",lastUpdatedTimeThreshold, ">")

  for conversation in listOfChats:
    conversationId = int(conversation['id'])

    if conversationIsQuarantined(conversationId):
      bodyForNote = 'Assigning to Quarantine Inbox because Conversation has been tagged as Quarantine'
      addNoteToConversation(conversationId, helperBotId,bodyForNote)
      assignConversationToAdmin(conversationId, 'admin',helperBotId,quarantineInboxId)
      continue

    contactId = getContactIdFromConversationObject(conversation)

    if contactId is None:
      continue

    if contactIsQuarantined(contactId):
      bodyForNote = 'Assigning to Quarantine Inbox because Contact has been tagged as Quarantine'
      addNoteToConversation(conversationId, helperBotId,bodyForNote)
      assignConversationToAdmin(conversationId, 'admin',helperBotId,quarantineInboxId)
      continue

    try:
      contactOwnerId = getContactOwnerId(contactId)
    except:
      contactOwnerId = None

    if contactOwnerId is not None:
      bodyForNote = 'Assigning to Owner of this Contact'
      addNoteToConversation(conversationId, helperBotId,bodyForNote)
      assignConversationToAdmin(conversationId, 'admin',helperBotId,contactOwnerId)
      continue

    try:
      conversationDict = getDictOfConversation(conversationId)
    except:
      print('XXXXXXXXXXXXXXXXXX Trouble getting dict of this conversation: ', conversationId)
      continue

    if checkIfAssigneeIsAdmin(conversationId):   #This means the conversation is already assigned to an admin.
      continue

    conversationPartList = []

    if 'conversation_parts' not in conversationDict or 'conversation_parts' not in conversationDict['conversation_parts']:
      return None


    for conversationPart in conversationDict['conversation_parts']['conversation_parts']:
      try:
        assignedToId = int(conversationPart['assigned_to']['id'])

        if assignedToId == None:
          if conversationPart['part_type'] == 'away_mode_assignment':
            assignedToId = int(conversationPart['part_type']['author']['id'])
        conversationPartList.append([conversationPart['created_at'],assignedToId])
      except:
        continue

    conversationPartList = listSortingFunction(conversationPartList)
    lastAssignee = ''

    for i in conversationPartList:
      if i[1] is None or i[1] in [helperBotId , inboxIdToProcess]:
        continue
      if i[1] not in inboxIdExclusionList:
        lastAssignee = i[1]

    if lastAssignee in teamMembers[inboxIdToProcess]:
      if admins[lastAssignee]['away_mode_enabled'] == False:
        if checkIfAdminIsActive(lastAssignee):
          bodyForNote = 'Conductor Bot Autoassignment Rule 4 to: ' + admins[lastAssignee]['adminName']
          addNoteToConversation(conversationId, helperBotId,bodyForNote)
          assignConversationToAdmin(conversationId, 'admin',helperBotId,lastAssignee)

def closeSelfServiceConversations(inboxToProcess, inboxNameToIdDict):
  inboxIdToProcess = inboxNameToIdDict[inboxToProcess]
  listOfChats = getListOfChatsBasedOnInboxAndState(inboxIdToProcess,'open')
  countOfConversationsClosed  = 0
  countOfScheduleDeliveryButtonsSelected = 0

  for conversation in listOfChats:
    currentTimestamp = int(time.time())
    conversationId = int(conversation['id'])
    conversationDict = getDictOfConversation(conversationId)

    conversationPartList = []

    if 'conversation_parts' not in conversationDict:
      continue

    for conversationPart in conversationDict['conversation_parts']['conversation_parts']:
      conversationPartList.append([conversationPart['created_at'], conversationPart['body'],conversationPart['part_type'],conversationPart['author']['type']])
    conversationPartList = listSortingFunction(conversationPartList)

    lastBodyMessage =''
    lastBotMessage =''

    scheduleRescheduleButtonClicked = False
    for i in conversationPartList:
      if i[1] is not None:
        if i[2] == 'comment':
          lastBodyMessage = i[1]
        if i[2] == 'comment' and i[3] == 'bot':
          lastBotMessage = i[1]

        if i[1].find('Schedule/Reschedule Delivery') > -1:
          scheduleRescheduleButtonClicked = True

    if scheduleRescheduleButtonClicked == True:
      countOfScheduleDeliveryButtonsSelected +=1
      if lastBodyMessage == lastBotMessage:
        if lastBodyMessage.find('To schedule or reschedule your delivery, please visit this')> -1:
          if currentTimestamp - conversation['updated_at'] > 60*15:
            bodyForNote = "Closing because this was self-service conversation that appears to have been resolved."
            addNoteToConversation(conversationId, helperBotId,bodyForNote)
            print(timeStamp(), '  Closed Self-service conversation: ',conversationId)
            closeAConversation(conversationId, helperBotId)
            countOfConversationsClosed +=1

def automateSalesFollowups(admins, teamMembers):
  listOfConversations = getListOfChatsBasedOnState("snoozed")
  print(timeStamp(), '  Script: Automate Sales Followups | # of Snoozed Conversations: ', len(listOfConversations))
  firstAutomatedFollowUpSentJustNow, actionAfterFirstGSFollowupCount, in48HourCoolingPeriodAfterFirstSalesFollowUp, in36HourCoolingPeriodAfterFirstGSFollowUp, daysSnoozedForwardLessThan24Days, conversationsSnoozedWithinLast18hours, deadConversationClosedJustNow, closeConversationAfterNoActionAfterFirstFollowup, closeConversationAfterNoActionAfterFirstGSFollowup , noGuestEmailAndSnoozed24Days, noGuestEmailAndNotSnoozed24Days,conversationsClosedAfterAgentTriesToDoSecondAutomatedFollowsup = 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0,0
  gotAllTheWayToEndCount = 0
  snoozedAfterSendFollowupWithoutAnyAdditionalAgentInteractionCount = 0

  for conversation in listOfConversations:
    conversationId = int(conversation['id'])

    try:
      assigneeId = int(conversation['assignee']['id'])
    except:
      print(timeStamp() , '  No assigneeID: ', conversationId)
      continue

    if assigneeId in teamMembers:
      bodyForNote = "Setting this conversation to OPEN because a conversation should be assigned to a team member before it is snoozed."
      addNoteToConversation(conversationId, helperBotId,bodyForNote)
      openAConversation(conversationId, helperBotId)
      continue

    if conversation['source']['author']['email'] == '':
      try:
        daysSnoozedIntoTheFuture = (conversation['snoozed_until'] -int(time.time()))/(60*60*24)
      except:
        daysSnoozedIntoTheFuture = 0
      if daysSnoozedIntoTheFuture > 24:
        timeSinceLastUpdate = int(time.time()) - conversation['statistics']['last_contact_reply_at']
        if timeSinceLastUpdate > 5*60*60:  #waiting 5 hours before sending this message
          bodyForNote = "Closing because guest did not leave email and we did not respond for 5 hours."
          addNoteToConversation(conversationId, helperBotId,bodyForNote)
          addMessageToConversation(conversationId, helperBotId,bodyForCommentWhenNoGuestEmail)
          closeAConversation(conversationId, assigneeId)
          noGuestEmailAndSnoozed24Days +=1
          continue
      else:
        noGuestEmailAndNotSnoozed24Days +=1
        continue

    try:
      hoursSinceLastAdminReply = (int(time.time()) - conversation['statistics']['last_admin_reply_at'])/float(60*60)
      if hoursSinceLastAdminReply < 18:
        conversationsSnoozedWithinLast18hours +=1
        continue
    except:
      pass

    conversationDict = getDictOfConversation(conversationId)
    conversationPartList = []

    for conversationPart in conversationDict['conversation_parts']['conversation_parts']:
      authorId = conversationPart['author']['id']
      conversationPartList.append([conversationPart['created_at'],authorId, conversationPart['body'], conversationPart['author']['type'], conversationPart['part_type']])

    conversationPartList = listSortingFunction(conversationPartList)
    gsFirstFollowUpBeforeClosing = False
    actionAfterFirstGSFollowup = False

    lastAction = None

    for i in conversationPartList:
      if i[2] is not None and len(i[2]) > 0 and i[4] != 'note':

        if i[3] == 'user':
          if gsFirstFollowUpBeforeClosing == True:
            actionAfterFirstGSFollowup = True

          lastAction = 'userRepliedToUs'

        if i[3] == 'admin':
          if i[2].find(bodyForCommentFromGSWhenNoActionYetFromUs)>-1:
            gsFirstFollowUpBeforeClosing = True
            lastAction = 'scriptSentGSCovidMessage'
          elif i[2].find(bodyForCommentWhenSnoozedOneMonthInFuture)> -1:
            lastAction = 'scriptSentFirstSalesFollowupMessage'
          elif i[2].find(commentTextForFinalFollow)> -1 or i[2].find(commentTextForFinalFollowupOld)> -1 :
            lastAction = 'scriptSentSecondSalesFollowupMessage'
          else:
            lastAction = 'agentRepliedWithMessageBeforeSnoozing'

    if lastAction == 'userRepliedToUs':
      try:
        #implemented this check because of potential for slight timing issue
        secondaysSinceLastContactReply = (int(time.time()) - conversation['statistics']['last_contact_reply_at'])
        if secondaysSinceLastContactReply < 120:
          continue
      except:
        pass

    if lastAction == 'scriptSentSecondSalesFollowupMessage':
      if conversation['source']['author']['email'] == '':
        bodyForNote = "Closing because guest did not leave email we had already sent followups to them."
        addNoteToConversation(conversationId, helperBotId,bodyForNote)
        addMessageToConversation(conversationId, helperBotId,bodyForCommentWhenNoGuestEmail)
        closeAConversation(conversationId, assigneeId)
        noGuestEmailAndSnoozed24Days +=1
        continue
      else:
        snoozedAfterSendFollowupWithoutAnyAdditionalAgentInteractionCount +=1
        continue

    if gsFirstFollowUpBeforeClosing == True and actionAfterFirstGSFollowup == False:
      if hoursSinceLastAdminReply > 36:
        noteTextWhenClosingGSConversation = admins[assigneeId]['adminName'] + ' - I am going to close conversation.'
        addNoteToConversation(conversationId, helperBotId,noteTextWhenClosingGSConversation)
        closeAConversation(conversationId, helperBotId)
        closeConversationAfterNoActionAfterFirstGSFollowup += 1
        continue
      else:
        in36HourCoolingPeriodAfterFirstGSFollowUp +=1
        continue

    if lastAction == None or lastAction == 'userRepliedToUs' or lastAction == 'agentRepliedWithMessageBeforeSnoozing':
      try:
        daysSnoozedIntoTheFuture = (conversation['snoozed_until'] -int(time.time()))/(60*60*24)
      except:
        daysSnoozedIntoTheFuture = 0
      if daysSnoozedIntoTheFuture > 20:  #change this back to 24 days at some point
        if conversation['source']['author']['email'] == '':
          print(timeStamp(), '  Closed this dead conversation with no guest email but had not chosen Sales assistance: ' , conversationId)
          noteText = admins[assigneeId]['adminName'] + ' - I am going to send a message on your behalf and then close conversation.'
          addNoteToConversation(conversationId, helperBotId,noteText)
          addMessageToConversation(conversationId, assigneeId,bodyForCommentFromChatGoesDeadAndNoGuestEmail)
          closeAConversation(conversationId, helperBotId)
          deadConversationClosedJustNow +=1
          continue
        else:
          noteText = admins[assigneeId]['adminName'] + ' - I am going to send a message on your behalf.'
          addNoteToConversation(conversationId, helperBotId,noteText)
          addMessageToConversation(conversationId, assigneeId,bodyForCommentWhenSnoozedOneMonthInFuture)
          snoozed_until = int(time.time()) + 60*60*24*30  #Snoozing for 30 days
          snoozeAConversation(conversationId, helperBotId, snoozed_until)
          firstAutomatedFollowUpSentJustNow +=1
          continue
      else:
        daysSnoozedForwardLessThan24Days += 1
        continue
    try:
      daysSnoozedIntoTheFutureFromAdminReply = (conversation['snoozed_until'] - conversation['statistics']['last_admin_reply_at'])/float(60*60*24)
    except:
      daysSnoozedIntoTheFutureFromAdminReply = 0
    if daysSnoozedIntoTheFutureFromAdminReply > 20:  #change this back to 24 days at some point
      if hoursSinceLastAdminReply > 48:
        if lastAction == 'scriptSentFirstSalesFollowupMessage':
          noteTextForFinalFollowup = admins[assigneeId]['adminName'] + ' - I am going to send a final message on your behalf and then close conversation because we have already done first automated followup in this conversation.'
          addNoteToConversation(conversationId, helperBotId,noteTextForFinalFollowup)
          addMessageToConversation(conversationId, assigneeId,commentTextForFinalFollow)
          closeAConversation(conversationId, assigneeId)
          conversationsClosedAfterAgentTriesToDoSecondAutomatedFollowsup += 1
          continue
      else:
        in48HourCoolingPeriodAfterFirstSalesFollowUp+=1
        continue
    else:
      daysSnoozedForwardLessThan24Days += 1
      continue


    # if conversation['statistics']['last_admin_reply_at'] is not None:
    #   daysSnoozedIntoTheFutureFromAdminReply = (conversation['snoozed_until'] - conversation['statistics']['last_admin_reply_at'])/float(60*60*24)
    #   if daysSnoozedIntoTheFutureFromAdminReply > 24:
    #     if firstSalesFollowUpAlreadySent == False:
    #       if conversation['source']['author']['email'] != '':
    #         noteText = admins[assigneeId]['adminName'] + ' - I am going to send a message on your behalf.'
    #         addNoteToConversation(conversationId, helperBotId,noteText)
    #         addMessageToConversation(conversationId, assigneeId,bodyForCommentWhenSnoozedOneMonthInFuture)
    #         snoozed_until = int(time.time()) + 60*60*24*30  #Snoozing for 30 days
    #         snoozeAConversation(conversationId, helperBotId, snoozed_until)
    #         firstAutomatedFollowUpSentJustNow +=1
    #         continue
    #       else:
    #         noteText = admins[assigneeId]['adminName'] + ' - we will close conversation.'
    #         addNoteToConversation(conversationId, helperBotId,noteText)
    #         addMessageToConversation(conversationId, assigneeId,bodyForCommentFromChatGoesDeadAndNoGuestEmail)
    #         closeAConversation(conversationId, helperBotId)
    #         deadConversationClosedJustNow += 1
    #         continue
    #   else:
    #     daysSnoozedForwardLessThan24Days +=1
    #     continue

    print(timeStamp(), '  All the way to the end: ', conversationId)
    gotAllTheWayToEndCount +=1

  print(timeStamp(), '  # of Conversations With No Guest Email But Not Snoozed 24 Days: ', noGuestEmailAndNotSnoozed24Days)
  print(timeStamp(), '  # of Conversations Just Closed With No Guest Email and Snoozed 24 Days: ', noGuestEmailAndSnoozed24Days)
  print(timeStamp(), '  # of Conversations Snoozed Within Last 18hours: ', conversationsSnoozedWithinLast18hours)
  print(timeStamp(), '  # of Conversations With Action After First GS Followup (will not be closed): ', actionAfterFirstGSFollowupCount)
  print(timeStamp(), '  # of Conversations With Snoozed Forward Less than 24 Days: '  , daysSnoozedForwardLessThan24Days)
  print(timeStamp(), '  # of Conversations in 48 Hour Cooling Period After First Sales FollowUp: ', in48HourCoolingPeriodAfterFirstSalesFollowUp)
  print(timeStamp(), '  # of Conversations in 36Hour Cooling Period After First GS FollowUp: ', in36HourCoolingPeriodAfterFirstGSFollowUp)
  print(timeStamp(), '  # of First Automated Sales FollowUps Sent Just Now: ', firstAutomatedFollowUpSentJustNow)
  print(timeStamp(), '  # of Conversations Just Closed That Were Snoozed 24 Days Into Future But No Guest Email: ',  deadConversationClosedJustNow)
  print(timeStamp(), '  # of Conversations Just Closed After No Action After First Sales Followup: ', closeConversationAfterNoActionAfterFirstFollowup)
  print(timeStamp(), '  # of Conversations Just Closed After No Action After First GS Followup: ', closeConversationAfterNoActionAfterFirstGSFollowup)
  print(timeStamp(), '  # of Conversations Just Closed After Agent Tried to do 2nd round of automated Followups: ', conversationsClosedAfterAgentTriesToDoSecondAutomatedFollowsup)
  print(timeStamp(), '  # of Conversations Where Agent Snoozed After 2nd Automated Followup Without Interacting: ', snoozedAfterSendFollowupWithoutAnyAdditionalAgentInteractionCount)
  print(timeStamp(), '  # of Conversations That Got All the Way to End: ', gotAllTheWayToEndCount)
  print(timeStamp(), '  # of Conversations That Are Accounted For: ', noGuestEmailAndNotSnoozed24Days + noGuestEmailAndSnoozed24Days + conversationsSnoozedWithinLast18hours + actionAfterFirstGSFollowupCount + daysSnoozedForwardLessThan24Days + in48HourCoolingPeriodAfterFirstSalesFollowUp + in36HourCoolingPeriodAfterFirstGSFollowUp + firstAutomatedFollowUpSentJustNow + deadConversationClosedJustNow + closeConversationAfterNoActionAfterFirstFollowup + closeConversationAfterNoActionAfterFirstGSFollowup + conversationsClosedAfterAgentTriesToDoSecondAutomatedFollowsup + gotAllTheWayToEndCount + snoozedAfterSendFollowupWithoutAnyAdditionalAgentInteractionCount)



def automatedGSFollowups(admins,inboxNameToIdDict):
  #Getting settings from this Google sheet: https://docs.google.com/spreadsheets/d/xxxxxx
  daysBeforeAutomatedGsFollowup, listOfInboxesToDoAutomatedFollowupsOn, listOfAgentsToDoFollowupWith = getIntercomAutomatedFollowupSettings()
  if daysBeforeAutomatedGsFollowup == 0 or listOfInboxesToDoAutomatedFollowupsOn == [] or listOfAgentsToDoFollowupWith == []:
    print(timeStamp(), '  Issue with current setting for Automated GS Followups')
    return None

  for inboxToDoAutomatedFollowupsOn in listOfInboxesToDoAutomatedFollowupsOn:
    inboxId = inboxNameToIdDict[inboxToDoAutomatedFollowupsOn]
    currentTimestamp = int(time.time())
    waitingSinceTimeThreshold = currentTimestamp - 60*60*24*daysBeforeAutomatedGsFollowup  #waiting X days before sending this message
    listOfChats = getListOfChatsBasedOnInboxAndStateAndLongestWaitingTime(inboxId,"open",waitingSinceTimeThreshold, "<")
    additionaListOfChats = getListOfChatsBasedOnInboxAndStateAndLastUpdatedTime(inboxId,"open",waitingSinceTimeThreshold, "<")
    for chat in additionaListOfChats:
      if chat not in listOfChats:
        listOfChats.append(chat)
    print(timeStamp(), '  checkIfGuestsStillNeedHelpInGSInboxes: ', inboxToDoAutomatedFollowupsOn, ' |Number of open chats: ', len(listOfChats))

    for conversation in listOfChats:
      if conversation['source']['author']['email'] == '':
        continue

      if conversation['source']['author']['type'] == 'admin': #this means it was an outbound message
        try:
          contactId = conversation['contacts']['contacts'][0]['id']
        except:
          continue
      else:
        contactId = conversation['source']['author']['id']

      conversationId = int(conversation['id'])
      eligibleForEmailFollowup = True
      lastAutomatedGSFollowup = getLastAutomatedGSFollowup(contactId)
      if lastAutomatedGSFollowup is not None:
        if (currentTimestamp - lastAutomatedGSFollowup) <  60*60*24*5:  #If it has been less than 5 days since last automated GSFollowup, we are just going to close the conversation.
          eligibleForEmailFollowup = False

      if eligibleForEmailFollowup:
        adminName = random.choice(listOfAgentsToDoFollowupWith)
        adminId = getAdminIdBasedOnName(adminName, admins)

        if adminId is None:
          print(timeStamp(), '  There is no admin Id for this admin name: ', adminName)
          continue

        contactDict = getContactDict(contactId)

        try:
          role = contactDict['role']
        except:
          print(timeStamp(), '  Issue getting role from contact Dict: ', conversationId, '|', contactId)
          continue
        bodyForNote = adminName + ' - I am going to send a message on your behalf.'
        addNoteToConversation(conversationId, helperBotId,bodyForNote)
        addMessageToConversation(conversationId, adminId,bodyForCommentFromGSWhenNoActionYetFromUs)
        snoozed_until = int(time.time()) + 60*60*24*15  #Snoozing for 15 days
        snoozeAConversation(conversationId, helperBotId, snoozed_until)
        email = conversation['source']['author']['email']
        updateContactCustomAttribute(contactId, email, role, 'LastAutomatedGSFollowup', currentTimestamp)
      else:
        bodyForNote = 'I am going to close this conversation because a final followup message was sent recently to this guest via a separate conversation.'
        addNoteToConversation(conversationId, helperBotId,bodyForNote)
        closeAConversation(conversationId, helperBotId)

def moveStalledKoreConversations():
  listOfChats = getListOfChatsBasedOnInboxAndState(koreBotId,'open')
  currentTimestamp = time.time()
  for conversation in listOfChats:
    lastUpdatedTimestamp = conversation['updated_at']
    conversationId = conversation['id']
    secondsSinceUpdate = currentTimestamp - lastUpdatedTimestamp
    if secondsSinceUpdate > 60:
      bodyForNote = 'Moving stalled conversation away from Kore.ai bot'
      addNoteToConversation(conversationId, helperBotId,bodyForNote)
      assignConversationToAdmin(conversationId, 'admin',helperBotId,gSGeneralInboxId)
      print ('Moved this stalled conversation away from Kore.ai: ', conversation['id'])

def moveEcommConversationsWhenNoTeamMembersAvailable(admins, teamMembers):
  listOfChats = getListOfChatsBasedOnInboxAndState(eCommerceInboxId,'open')
  if len(listOfChats) == 0:
    return None

  countOfConversationsMoved = 0
  stringOfConversationsMoved = ''

  for conversation in listOfChats:
    conversationId = conversation['id']
    assignConversationToAdmin(conversationId, 'admin',helperBotId,rtGeneralInboxId)
    stringOfConversationsMoved += str(conversationId) + ', '
    countOfConversationsMoved +=1

  if countOfConversationsMoved > 2:
    date = getTodaysDate()
    printableDate  = str(date)[:4] + '-' + str(date)[4:6] + '-' + str(date)[6:]
    fromEmailFriendly = 'Ecomm Conversations Moved to RTGeneralInbox'
    subject = 'Ecomm Conversations Moved to RTGeneralInbox on ' + printableDate
    recipientList = getRecipientListFromGoogleSheets('IntercomConductorBot', 'ReassigningEcommerce')
    bodyString = timeStamp() + ' - Number of Ecomm Conversations Moved to RTGeneralInbox: ' + str(countOfConversationsMoved)
    bodyString += '<br><br>'
    bodyString += 'List of conversations moved: ' + stringOfConversationsMoved
    sendEmailViaSendGrid(fromEmailFriendly,recipientList,subject,bodyString,None,None)


#####################################################################################################################
##################################################   MAIN   ####################################################################
print('-------------------------------------------------------------------------------------------------------------------------------')
print(timeStamp(), '  Start')

admins, teamMembers, inboxNameToIdDict = getAdminsandTeamMembersDicts()
startTime = time.time()
elapsedSeconds = 0
iteratorCount = 1

while elapsedSeconds < 60*58:
  moveStalledKoreConversations()
  closeSelfServiceConversations('Unassigned', inboxNameToIdDict)
  closeSelfServiceConversations('GS General', inboxNameToIdDict)
  closeSelfServiceConversations('GS Time Sensitive', inboxNameToIdDict)
  moveEcommConversationsWhenNoTeamMembersAvailable(admins, teamMembers)

  if iteratorCount % 11 == 0:
    for combo in [['RT General',['RT General']],['GS Warranty Claims',['GS General']], ['GS General',['GS General']],['GS Time Sensitive',['GS General']],['GS Post-delivery Issues',['GS General']],['GS Status',['GS General']]]:
      pushInboxConversationsToApplicableAgents(combo[0],combo[1], inboxNameToIdDict, teamMembers, admins)

  if iteratorCount % 20 == 0:
    for inboxToCloseWhenNoEmail in ['RT General','GS Time Sensitive','GS General', 'GS Warranty Claims',  'GS Status','GS Post-delivery Issues','GS Feedback Form']:
      closeOldConversationsWithNoGuestEmailFromInboxes(admins,teamMembers, inboxNameToIdDict, inboxToCloseWhenNoEmail)

  # if iteratorCount % 22 == 0:
  #   if getCurrentHour() in [7,8,9,10,11,12,13,14,15,16,17,18]:
  #     automateSalesFollowups(admins, teamMembers)

  if iteratorCount % 23 == 0:
    daysBackThresholdForClosingBasedOnSisterChats = 3
    daysDeltaRequiredToClose = 1
    for gsInbox in ['GS Time Sensitive', 'GS General', 'GS Warranty Claims',  'GS Status','GS Post-delivery Issues','GS Feedback Form']:
      findChatsToCloseBasedOnSisterChats(admins,teamMembers, gsInbox, inboxNameToIdDict, daysBackThresholdForClosingBasedOnSisterChats,daysDeltaRequiredToClose)

  if iteratorCount % 24 == 0:
    updateContactsWithoutEmailsButDoHaveMktEmails()

  if iteratorCount % 25 == 0:
    if getCurrentHour() in [10,11,12,13,14,15,16,17,18]:
      # automatedGSFollowups(admins,inboxNameToIdDict)   This was causing issues with the communication of the covid message.
      admins, teamMembers, inboxNameToIdDict = getAdminsandTeamMembersDicts()


  iteratorCount += 1
  elapsedSeconds = time.time() - startTime

updateScriptStatusInPythonMasterLogGoogleSheet('IntercomConductorBot')
print(timeStamp(), '  Done')

Add flush=True to your prints, that would prevent buffering.