6 Replies Latest reply: Dec 4, 2012 5:48 PM by Hiroto
Bernard Harte Level 4 Level 4 (3,050 points)

I have an AppleScript saved as a run only app which I call every hour from launchd.

 

Most of the time it works fine, but occasionally something causes the app not to quit when it's done its thing.  This means that next time an error is thrown and the process does not run (so it fails until I force quit the app).

 

I have tried wrapping the whole script in a try...with timeout...end timeout...on error return...end try structure but that makes no difference.

 

The core of the script is a run shell script that calls a perl script which in turn gets data from a web site.  I have tried nesting a try...on errror...end try around this that simply sets the content of the variable that should be populated from the script in the event that any error occurs.

 

The final part of the script is opening a [text] file and inserting a few lines at the top.  Again I have tried wrapping this in a try...on error return...end try stricture.

 

None of these efforts seems to have any effect.  However, I can't get the script to fail when I run it from the ApplScript Editor.

 

Would I be better to use osascript to call a script rather than the app, or am I doing something more fundamental wrong?


MacBook Pro, OS X Mountain Lion, MacBook Pro Late 2011 8GB RAM
  • 1. Re: Ensure AppleScript App Quits
    twtwtw Level 5 Level 5 (4,690 points)

    This is way too non-specific for me to venture anything but the most generic advice.  You either need to show us the script or explain it more clearly.

     

    The one question I do have is if this script is just a wrapper for a perl script, why not run the perl script directly from launchd and skip the applescript middleman?

  • 2. Re: Ensure AppleScript App Quits
    Bernard Harte Level 4 Level 4 (3,050 points)

    I'm sorry you find the question 'way too non-specific', I had tried to give all the detail I could.

     

    I am not running the perl script directly as it's only a single part of the process: the data retrieval.  I daresay I could write the whole thing in perl, but I am comfortable with manipulating the data; checking for condition(s) and writing to file with AppleScript.

     

    Let me ask the question another way:  If the previous execution of the app fails and the app is still running/hanging, could I wrap the entire process in another script (whatever language) to force it to quit before commencing the run?

  • 3. Re: Ensure AppleScript App Quits
    twtwtw Level 5 Level 5 (4,690 points)

    Maybe, depending...  Of course, that's the last approach I'd usually try, because it's bound to be clunky.

     

    Don't get me wrong. I'm not asking you for more detail to be annoying.  I'm asking because without knowing what kind of hang/failure you're experiencing (or even what you're trying to do, for that matter) I'd just be shooting in the dark.  You want a formulaic answer, but there isn't one, at least not at this level of abstraction.

     

    Again with the generic advice: you do know that you can call a script app's handlers from other applescripts, right? So if you want to quit an app programatically just write a script that tells it to quit (or that calls a different handler that does cleanup before it quits).  That won't work if the script is truly frozen - Applescript is not threaded, so it has to finish one script command before it can begin another - but if the script app has simply stopped (as sometimes happens) it should still respond to handler calls.

     

    just out of curiosity, I'm assuming you saved this as a stay-open app (since part of the problem is that it stays open - lol); did you add an on idle handler?  without an idle handler the script will just sit there waiting for something to call one of its other handlers.  you need the idle handler if you want the app to check in periodically.

  • 4. Re: Ensure AppleScript App Quits
    Bernard Harte Level 4 Level 4 (3,050 points)

    I'm not trying to be coy either, but I don't see that posting the whole script is going to help particularly because the perl script uses WWW::Mechanize to get data from a website where I have to provide user credentials - hence, it will not be possible to run it without those credentials.

     

    The expectation is that I will get approximately ten lines of data back (which I put into a local variable).  I then use an offset check to determine whether a particular string is present.  If it is present, I then go on to compose a message (using Messages) to send to myself.

     

    Regardless of the content, I open a local text file and insert the web response at the beginning of the file (as an activity log).  The file is then closed for access and that's it.

     

    I have only once seen an error when I ran the script from the AS Editor and this seemed to indicate a problem with the site's availability - so when Mechanize couldn't find any identifiable data, it threw an error.

     

    The app is not saved as stay open, but it does.  All I can say for certain is that the log file does not get written to, so I suspect that the problem lies with the perl script.  It is for that reason that I wrapped it in a try...with timeout structure.  (My understanding of the timeout, is that if script execution fails to complete within the timeout an error will be thrown, so this is picked-up by the try...on error.  That understanding may be wrong.)

     

    So, after all that, here is the script [with a single hard-coded address obscured for privacy]:

     

    try

              set desktopPath to (path to desktop) as alias

              set FlightCheckLog to (desktopPath as text) & "FlightCheckLog.txt"

              set targetList to {"Sep-7", "Sep-8", "Sep-9", "Sep-10"}

     

              tell application "Messages"

                        set theBuddy to buddy id "<OBSCURED>"

              end tell

              set messageSent to false

     

              try

                        with timeout of 300 seconds

                                  set theFlights to do shell script "~/Documents/perl/FilghtCheck.pl -x -c J -d 2013-09-07 ATH-LHR"

                        end timeout

              on error

                        set theFlights to ""

              end try

     

              repeat with theDate in targetList

     

                        set theOffset to (offset of theDate in theFlights)

                        if theOffset is not 0 then

                                  set theFlight to text (theOffset - 5) thru end of theFlights

                                  set theReturn to (offset of return in theFlight)

                                  set theFlight to text 1 thru (theReturn - 1) of theFlight

     

     

                                  tell application "Messages"

      send theFlight to theBuddy

                                            set messageSent to true

                                  end tell

                        end if

     

              end repeat

     

              try

                        set theFile to open for access FlightCheckLog with write permission

     

      get eof theFile

     

                        if result > 0 then

                                  set fileText to read theFile

      set eof theFile to 0

                        else

                                  set fileText to ""

                        end if

     

     

                        if messageSent then

                                  write ((current date) & return & theFlights & return & "MESSAGE SENT" & return & return & fileText) as text to theFile

                        else

                                  write ((current date) & return & theFlights & return & return & fileText) as text to theFile

                        end if

     

      close access theFile

              on error

                        return

              end try

     

    on error

              return

    end try

  • 5. Re: Ensure AppleScript App Quits
    twtwtw Level 5 Level 5 (4,690 points)

    A couple of style points that will make debugging easier.  If you use try blocks, use the following pattern (which gives error feedback) and put the try blocks around the smallest units possible (which helps identify where the error is happening):

     

    try

      -- a command

    on error errstr

              tell application "System Events" to display dialog errstr

              return

    end try

     

    keep in mind that a script app may not always report errors the same way as a running script, which is why I directed the DD to System Events.

     

    That being said, the only places it seems to me this script could get stuck are with the shell script and open file commands.  However, if the shell script were to hang it would not throw an error; the script would merely move on after 5 minutes, and you'd get an error that the variable theFlights has not been set.  forget that try block and do it this way instead:

     

    set theFlights to ""

    with timeout of 300 seconds

              set theFlights to do shell script "~/Documents/perl/FilghtCheck.pl -x -c J -d 2013-09-07 ATH-LHR"

    end timeout


    File access can fail if there's already an open pointer to the file - Applescript only allows one pointer, and for some reason throws an error rather than returning the open pointer.  whenever I do file access during testing I use thin pattern, which tries to close open pointers and reopen the file:

     

    try

              set theFile to open for access FlightCheckLog with write permission

    on error

      close access FlightCheckLog

              set theFile to open for access FlightCheckLog with write permission

    end try

     

    So, get rid of that all-encompassing try blocks, make the changes I've suggested to the other try blocks and the file open line, and tell me what happens.

  • 6. Re: Ensure AppleScript App Quits
    Hiroto Level 5 Level 5 (5,025 points)

    Hello

     

    The 'with timeout' statement does not apply to osax command.

    Try the following code and see it returns true.

     

    try
        with timeout of 1 second
            do shell script "sleep 3"
        end timeout
        return true
    on error errs number errn
        return {errs, errn}
    end try
    

     

    I think your perl script is hanging.

    Make sure it does exit or die properly.

     

    Regards,

    H