Search code examples
pythonfor-loopif-statementsleep

Issue with sleep inside for loop


I have a condition in my python code wherein if the condition is met, it should send an email. When the same condition is executed again, it should wait for 60 min before it can send another email. I used an if inside for loop but the issue is that the other rows in the for loop are stuck because of the if loop inside. How do I overcome this?

def send_email(previousindex,index):
    if previousindex!= index or previousindex is None:
        print('email sent')
       
    else:
        print('Wait for 1 hr')
        time.sleep(3600)


while True:
    previousindex = None
   

    for index in df.index:  # row in df.iterrows():

        if df.loc[index, 'Time flag'] == 1:
            print('fail')
            print(previousindex)
            send_email(previousindex,index)
            previousindex = index
            
        else:
            time.sleep(10)
            continue
               



    time.sleep(10)

def send_email(previous_index, index):
    if index not in previous_index:
        print('email sent')

    else:
       print(previous_index)

       print('Wait for 1 hr')
       time.sleep(3500)
       previous_index.clear()

       print('email sent')


while True:
    df = pd.read_csv(r'C:/Users/KrishnamurthyKA/Desktop/Project/Test.csv',sep = ',')

    for index in df.index:  # row in df.iterrows():

        if df.loc[index, 'Time flag'] == 1:

            print('pass')
            send_email(previous_index, index)
            previous_index.append(index)
            print(previous_index)

            # if previousindex == index:

            # print('entered if loop')
            # print(previousindex)
            # time.sleep(10)
        else:
            time.sleep(10)
            continue

    print(previous_index)
    time.sleep(10)

EDIT 2:

min = 2
 while True:
for index in df.index:
    now = datetime.datetime.now()

    if df.loc[index,'Time flag'] == 1 and df.loc[df.index[index], "Last_email_sent"] == None:
        print('pass')
        df.loc[df.index[index], "Last_email_sent"] = now
        print(now)

        #send_email(index)
    elif df.loc[index, 'Time flag'] == 1 and minutes < min:
        print('wait')
        print(minutes)
        print(df.loc[index,'Last_email_sent'])

    elif df.loc[index, 'Time flag'] == 1 and minutes >= min:
        #send_email(index)
        print('sending email after 1 min')
        df.loc[index, "Last_email_sent"] = now

        print(minutes)
        minutes = divmod((now - df.loc[index, "Last_email_sent"]).total_seconds(), 60)[0]
    else:
        print('false')


time.sleep(10)

Solution

  • First, your logic can be simplified into:

    while True:
        previous_index = None
    
        for index in idx:
            # First iteration
            if condition(index) and previous_index is None:
    
                send_email()
                previous_index = index
    
            elif condition(index) and previous_index != index:
    
                send_email()
                previous_index = index
    
            elif condition(index) and previous_index == index:
    
                # Wait 1 hour
                time.sleep(3600)
    
            else:
                time.sleep(10) # Wait a bit
                continue
    

    From my interpretation, you get stuck because the process stops during 1 hour every time it enters the time.sleep(3600). Thus during this time, you would like the rest of the loop to keep running on other index.

    The problem is that time.sleep() pauses the opened python process during the time specified. One way to overcome this is to open an additional process to send the e-mail. The code would look like:

    def send_email(previous_index, index):
    
        if previous_index != index or previous_index is None:
            # Send the e-mail
        else:
            # Wait 1 hour
            time.sleep(3600)
            # Send the e-mail
    
    while True:
        previous_index = None
    
        for index in idx:
            if condition(index):
    
                Open_process(target = send_email, args = (previous_index, index))
                previous_index = index
    
            else:
                time.sleep(10) # Wait a bit
                continue
    

    Processes have the disadvantage to be a bit slow to open. Threads might be better, however, as you included a sleep of 10 second between each loop, I don't think it matters in this application.

    Finally, you can look at the library multiprocessing to manage processes.

    EDIT:

    def send_email(index):
        # Function sending the e-mail
        print ("e-mail sent")
    
    # Each index is unique and the loop is executed every 10 s
    # Key: index; Value: number of iterations; 360 iterations = 1 hour.
    tracking = dict()
    # Initialize with None
    for index in df.index:
        tracking[index] = None
    
    while True:
    
        for index in df.index:
    
            if df.loc[index, 'Time flag'] == 1 and tracking[index] is None:
                send_email(index)
                tracking[index] = 1
    
            elif df.loc[index, 'Time flag'] == 1 and tracking[index] < 360:
                tracking[index] += 1
    
            elif df.loc[index, 'Time flag'] == 1 and tracking[index] == 360:
                send_email(index)
                tracking[index] = 1 # Reset since an e-mail is sent.
    
            else:
                # df.loc[index, 'Time flag'] == 0
                tracking[index] = None
    
        time.sleep(10)
    

    EDIT 2

        def send_email(index):
            # Function sending the e-mail
            print ("e-mail sent")
    
        # Add column to keep tack of last e-mail send timing
        # If the e-mail has never been sent, initialize to Nan, None, or -1
        # No idea what is more convenient, but adapt the first if accordingly
        df.add_column("Last e-mail sent timing")
    
        while True:
    
            for index in df.index:
    
                if df.loc[index, 'Time flag'] == 1 and df[index, "Last e-mail sent timing"] is None:
                    send_email(index)
                    df[index, "Last e-mail sent timing"] = current.time()
    
                elif df.loc[index, 'Time flag'] == 1 and current.time - df[index, "Last e-mail sent timing"] < 1 hour:
                    # skip
                    continue
    
                elif df.loc[index, 'Time flag'] == 1 and current.time - df[index, "Last e-mail sent timing"] >= 1 hour:
                    send_email(index)
                    df[index, "Last e-mail sent timing"] = current.time()
    
            time.sleep(10)
    

    EDIT 3:

    duration_to_wait = 2 # in MINUTES
    
    while True:
    
        for index in df.index:
    
            if df.loc[index,'Time flag'] == 1 and df.loc[df.index[index], "Last_email_sent"] == None:
                send_email(index)
                df.loc[df.index[index], "Last_email_sent"] = datetime.datetime.now()
    
            elif df.loc[index, 'Time flag'] == 1 and datetime.datetime.now() - df.loc[df.index[index], "Last_email_sent"] < datetime.timedelta(minutes=duration_to_wait):
                print('Wait')
                print(datetime.datetime.now() - df.loc[df.index[index], "Last_email_sent"])
    
            elif df.loc[index, 'Time flag'] == 1 and datetime.datetime.now() - df.loc[df.index[index], "Last_email_sent"] >= datetime.timedelta(minutes=duration_to_wait):
                send_email(index)
                df.loc[index, "Last_email_sent"] = datetime.datetime.now()
    
            else:
                print('false')
    
        time.sleep(10)