0

I am using a borrowed Python script which has two function definitions (get_data and get_data_multiple) within a class defined outside the main function. The main function calls get_data_multiple which in turn calls get_data. In short, my code fetches Pi Data using win32com module (from win32com.client.dynamic import Dispatch).

The goal is to run the main function every hour. I am doing this by using a while True: loop and the time.time() from time module. In some rare cases, I find that call to get_data takes too long to send a return value to get_data_multiple. In those cases, my code crashes as by the time, the return value to main arrives, its already past an hour.

I want to add a logic, where I terminate the call to get_data and force it return a default value if the time spend within it has crossed beyond a certain time. I know that the function spends too much time in the line pi_values = tag.Data.InterpolatedValues2(t_start, t_end, t_interval, asynchStatus=None). How can I do this, when I don't have a return value available from function ?

def get_data(self, tag_name, t_start, t_end, t_interval):
        """Retrieve interpolated data from the PI-server

        Args:
            tag_name (str): PI tag name
            t_start (str): PI time format (ex. '*-72h')
            t_end (str): PI time format (ex. '*')
            t_interval (str): PI time format (ex. '1h')

        Returns:
            pandas dataframe: index=datetime, col_1=interpolated values
        """

        logger.info('get_data for tag `%s`' % tag_name)
        tag = self.pi_srv.PIPoints(tag_name)
        pi_values = tag.Data.InterpolatedValues2(t_start, t_end, t_interval, asynchStatus=None)
        return (self.pivalues_to_df(pi_values, tag_name))

def get_data_multiple(self, tags, t_start, t_end, t_interval):
        """Retrieve interpolated data from the PI-server for multiple tags

        Args:
            tags (list): List of PI tag names
            t_start (str): PI time format (ex. '*-72h')
            t_end (str): PI time format (ex. '*')
            t_interval (str): PI time format (ex. '1h')

        Returns:
            pandas dataframe: index=datetime, cols=interpolated values

        """
        logger.info('getting data for %s tags' % len(tags))
        list_of_values = []
        pBar = ProgressBar()
        for i,tag in enumerate(tags):
            print(i)
            df = None
            while df is None:
                try:
                    df = self.get_data(tag, t_start, t_end, t_interval)
                except:
                    print('Connection Timeout. Retring.....')
                    pass
            # drop duplicated indices -> result of summer-to-winter time 
            # transition. Not doing this results in the subsequent join() to 
            # spiral out of control
            df = df[~df.index.duplicated()]
            list_of_values.append(df)


        df_values = pd.DataFrame().join(list_of_values, how='outer')
        #print(df_values.columns)
        return df_values
chupa_kabra
  • 465
  • 2
  • 5
  • 15
  • 4
    I think you could try to spawn a new process and set a timeout on it - view other solutions here https://stackoverflow.com/questions/492519/timeout-on-a-function-call – PYPL Nov 11 '19 at 05:18
  • 2
    Spawn a thread. Please see [this QA](https://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread) – Pynchia Nov 11 '19 at 05:26

1 Answers1

0

You can try this:

import signal

def signal_handler(signum, frame):
    raise Exception("Timed out!")

and in your code:

signal.signal(signal.SIGALRM, signal_handler)
signal.alarm(10)   # Ten seconds
try:
   pi_values = tag.Data.InterpolatedValues2(t_start, t_end, t_interval, asynchStatus=None)
except:
    print "Timed out!"

and set a default value for pi_values in the except clause

oppressionslayer
  • 6,942
  • 2
  • 7
  • 24
  • Thanks for the answer. But I am running this on a windows platform and it gives an error ```module 'signal' has no attribute 'alarm'```. – chupa_kabra Nov 11 '19 at 05:27
  • Ok, i found this, it may be of help: https://stackoverflow.com/questions/21827874/timeout-a-python-function-in-windows – oppressionslayer Nov 11 '19 at 06:47