Shortcuts called from AppleScript - not running consistently

Recently heard David and Rose talk about mixing automation tools and was working on some Applescript so I decided to try it.

I’d been getting a formatted date/time using shell commands from within Applescript. I was finding that this would randomly misbehave (stall and timeout). So I created a simple Shortcut to replace the handler that calls the shell script (link to shortcut attached). Seemed to work OK over the weekend when I built it. Yesterday and today I seem to be running into the same situation I had with the script.

Specifically, the script I have built that calls log_event from Hazel would not run. So I have been attempting to debug using ScriptDebugger. I found that when I would step into the handler that getFormattedCurrentDateTime is stalling. I then went to the Shortcuts app and ran the shortcut and it worked just fine. Then magically the Applescript started to work again.

Perhaps there is something about my scripts that causes these issues. Perhaps something about my Mac. I am using a 2021 16" M1 MacBookPro and I installed MacOS 12.5 before I built getFormattedCurrentDateTime.

Obviously automations that are not reliable are really troublesome. I would think that using Apple’s own tools would be the lowest risk. But I have had problems like on & off for years.


Here is my Shortcut
https://www.icloud.com/shortcuts/84959e0ab7414a538aa3bae2464933db


The handler that calls the shortcut is getFormattedCurrentDateTime

on getFormattedCurrentDateTime()
	tell application "Shortcuts"
		local currentDateTime, currentDateTrimmed
		
		set currentDateTime to run shortcut "Get formatted current date-time"
		
		-- We can do this because we know we are only getting a single date-time		
		set currentDateTime to contents of currentDateTime as string
		
		set currentDateTimeTrimmed to my trimWhiteSpaceFromEnds(currentDateTime)
		
		return currentDateTimeTrimmed
	end tell
end getFormattedCurrentDateTime


getFormattedCurrentDateTime is being called by the handler log_event, I use it to write out log files from my Applescripts. The first try block starts with a call to getFormattedCurrentDateTime and this is where things hang up, sometimes.

type or paste code here

on log_event(GeneralLogFilePosixPath, theMessage)
	-- It is assumed that the scripts calling this function determine if/when/where to write out a log.
	-- The logfiles include the date and the the POSIX path provided into this function.  The log
	-- entry includes the date/time of the log entry and the message passed into the function.
	
	local theDateTimeString, theLogString, theLogFilePath, fileExists, positionString, theLogFile
	
	try
		set theDateTimeString to my getFormattedCurrentDateTime()
		
		set theLogString to theDateTimeString & " " & theMessage & "\n"
		
		set theLogFilePath to my getLogFilePath(GeneralLogFilePosixPath)
		
		set fileExists to my doesFileExist(theLogFilePath)
		if fileExists then
			set positionString to "EOF"
		else
			set positionString to "TOP"
		end if
		set wasWritten to my writeToFile(theLogFilePath, positionString, theLogString)
		
		if not wasWritten then
			set errMsg to "Logging:log_event: The log file " & theLogFilePath & " did not get written with " & theLogString
			my throwError(errMsg)
		end if
		return wasWritten
	on error theError
		try
			set theDateTimeString to my getFormattedCurrentDateTime()
			
			set theNewMessage to "CTlib:log_event: Error (" & theError & ") writing a log entry out to" & theLogFilePath & "the entry was " & theLogString
			
			set theLogFilePath to my getLogFilePath(GeneralLogPOSIXPath)
			
			set theLogFile to my writeToFile(theLogFilePath, "EOF", theNewMessage)
			
		on error theNewError
			set errorMessage to "UNKNOWN ERROR IN CTlib:log_event"
			display alert theNewError message errorMessage
		end try
		return false
	end try
end log_event

Edit: fixed the code

In my experience shortcuts don’t like being called from outside of Shortcuts. It’s either unreliable or slow. Shortcuts is great for many many things, but not for “back and forth” operations.

If all you need is date formatting, I’d skip Shortcuts altogether and go with a shell command (and I’m pretty sure it works faster).

set currentDateTime to (do shell script "date \"+%Y_%m_%d %H:%M:%S\"")

Does this work more reliably?

Cheers

I had hoped the new Shortcuts would benefit from Apple’s attention so I wanted to try this out after hearing David & Rose talk about mixing and matching tools. Obviously not as good as I had hoped.

I have been using handlers that use “do shell script” for a while. My results have been less than optimal. I routinely ended up with Hazel notifications of a failed script and my log files indicating that the issues are in these shell script handlers. I replaced one such handler with the Shortcut in the hope of better performance. No such luck.

Even running AppleScript in ScriptDebugger I find the behavior to be inconsistent and that really does not work well in an automation.

I do not feel I am proficient enough with AppleScript to think I am not the source of these errors but I also have been writing software since the mid-‘70s so I am not quite a newb.

So I am hoping to get a sense for what other users are observing.

1 Like

I, personally, dislike calling out to other shells or processes unless there’s a very good reason to do so. There will be extra overhead in doing this, and so initially performance can also be affected, even though as @sebastienkb pointed out, a shell script can often be quicker to a sufficient enough extent to offset the cost incurred from initialisation.

Likewise, with the Objective-C bridge, the performance will often outweigh the extra overhead for large scripts.

However, it seems to me that a lot of the times people call out to other languages is because it wasn’t clear how to do a portion of the task in AppleScript itself. Date manipulation is one of the common scenarios. But, as you’ve observed, you can run into problems if a shell process hangs for whatever reason, or if environment variables aren’t set up the way one might be accustomed to in a terminal. Additionally, you have to ensure the shell script exits with an exit status of zero, otherwise it throws an error. There can be some timing issues as well, although this is common with many external or third-party resources.


AppleScript dates

It’s not clear what format you want the date and time to be in. I, personally, favour the international standard ISO-8601 format, which @sebastienkb exemplified in his shell script.

To obtain the full ISO-datetime formatted string, you can use a shortcut in AppleScript:

return (the current date) as «class isot» as string
    --> 2022-08-05T10:35:47

Or you can take that string and manipulate it into your preferred arrangement, e.g.

tell (the current date) as «class isot» as string ¬
        to tell [word 1, word 2, text 9 thru 10, ¬
        text 12 thru 13, word -2, word -1] to ¬
        return its contents as text
    --> 20220805103547

Each of those elements in the list represent a two digit portion of the date or time in order, but you can put them in any order you wish, as well as insert items of text between them to delimit components.

Really cool solution @chri.sk I didn’t know we could format dates within AppleScript. I’m off to edit a bunch of scripts now! :grin:

1 Like

Is it possible Shortcuts and Applescript are running asynchronously relative to each other? And hence not reliably sequenced?

I think you might need to swap the M (minutes) with the m (month) there.

Oof :man_facepalming: Thanks for the lookout! I’ll fix it in my original reply too in case someone copies that…

1 Like

Chris is correct I had not figured out how to format dates in AppleScript so I too will be looking to add this to my scripts.

I have several AppleScripts where I invoke “do shell script” and I find them all to be unreliable. Specifically I randomly find my AppleScripts failing because the shell scripts timeout. The shell script I used to format dates being my most recent experience. I was trying Shortcuts to see if it was more reliable. I found out quickly that it was not.

I would stay in one tool set 100% of the time if I could find one that supports all of the tasks I want to perform. Unfortunately it seems like none of the tools available are “fully baked”. So I am trying to figure out which tools are best for which tasks.

It appears that I have a bunch of work left to do.

Thanks again everyone!

Thank goodness forums like this exist to help.

Well, I hope not! Interop behavior is not incredibly well documented by Apple, they just promise “It Just Works”.

In theory AppleScript waits for the exit of whatever it calls. However what does qualifiy as “a good exit” in the eyes of AppleScript may vary in the executed code and end up in a timeout, like when Shortcuts engine crashes and AppleScript reaches a timeout because of that.

When I’m invoking Shortcuts from outside of Shortcuts I feel that I’m waking up an old God from its slumber. Doesn’t feel fast like AppleScript to me. Much more enjoyable to write though. Are there benchmarks on this?

Also Shortcuts is young and many bugs need to be discovered. I’ve lost count on the times that even “normal” use of plain Shortcuts will simply result in an error-less non-execution and/or a timeout. On bad cases I need to restart iOS/macOS when Shortcuts don’t run.

One last thing before I let this topic rest: do you confirm that the called Shortcut always returns something (e.g. a default string), and that when returning it returns a string type as well? I’ve had issues with some of mine because the returning type was not guaranteed to always return a string, regardless if the Shortcut worked well or not.

I do nothing to confirm that a string is always returned other than looking at the documentation for the actions provided by Apple. I figured that this is a pretty basic script using only Apple’s actions (not 3rd party actions).

My shortcut has 4 actions:

  1. Executes the Date action to get the current date (output: date according to Apple)
  2. Set named variable currentDate to the date (output: same type as step 1)
  3. Format the currentDate to be yyy_MM_dd HH:mm:ssZ (output: text according to Apple)
  4. Stop and output the formatted date (which according to Apple should be text).

I am only reformatting the one piece of data, changing a date into text using the Unicode standard Apple ID’s in their documentation.

I tested this when I built it and after confirming the formatted date was what I wanted I see nothing in my script that could result in text not being output. I could be wrong of course.

If there is an error passed along to me from Apple I am not sure how to handle that with the tools we are provided.

What are you thinking might happen and what I might do?

I had 3 occurrences where shortcuts would behave bizarrely, but all 3 depended on If/Else cases which I doubt you have in your shortcut (given how straightforward it is). I’ll list them in case it can be of inspiration to others.

  1. The return types were different in an If/Else; i.e. if my condition was true it returned 1 (Number) otherwise it returned False (Boolean). Fix: Switching both types to Boolean.

  2. there were cases where there was a return value, and cases where the shortcut ends without returning at all; e.g. if hour between 6-8 return this; if between 16-20 return that; and for all other cases do nothing at all (no returns). Fix: Add a Return action at the very end in case no other cases were hit.

  3. the shortcut has a proper return action for each case, but the returned value was a variable that may not be initialized. Fix: Leave no variable empty and initialize them early in the shortcut just in case we miss all future opportunities to be initialized.

Thanks for the help with this!