Jump to content
bikeNik

[SOLVED] To launch two JS files concurrently with one command.

Recommended Posts

Hello, Alfred's community! I can't solve the following problem:


My workflow in NodeJS environment. I've got two files. And I run them.
1. index.js for launching my processes ( [script filter]   with "titles, subtitles" on the output)

./node_modules/.bin/run-node index.js "$1" "headword"

and
2. refresh.js for refreshing JSON data ([Run Script]   background process)

./node_modules/.bin/run-node src/cmd/refresh.js "#runref"

 

I'm launching (concurrently) both of these files via TWO commands: 
1. by [keyword] (launching processes) - index.js
and
2. by [enter] on some operation of the previous result in the launching process of index.js, I'm launching - refresh.js

554559400_Screenshot2018-12-03at16_31_56.png.b2468c0b36a49258510f648903a4e79a.png

 

So, my question: Is there any way to launch (concurrently) both of these files by ONE command. By [keyword].
Thnx!

Share this post


Link to post

It should work if you connect the same Keyword to two Run Scripts, or if you have both commands in the same Run Script and append a & to the first one, to send the job to the background.

 

But when asking for help with a Workflow, please upload it somewhere so we can properly help you. Debugging can already be hard with access to the code, and you’re asking us to guess yours from a description. There are multiple places where your code or Workflow setup may be going wrong. Without looking at it we’re shooting in the dark.


Read the Reporting Problems with Workflows topic, as it gives a nice overview on how to build an effective report.

Share this post


Link to post

 

@vitor

I'll try to work something out with your suggestions - many thanks.

I think this workflow is too complicated for testing this feature at this moment. Requires: Node.js 7.6+ and  Anki intelligent flashcards. I'll reproduce it with another workflow.

Thnx again!

 

Share this post


Link to post

I made another workflow. disk.yandex.ru (19mb)

 

This workflow generates (in 5 seconds! as the imitation of network request) JSON file with current time data.

In the format like - [HR:MIN:SEC].

937706522_Screenshot2018-12-03at22_04_43.png.f2ef350fe2eab1076f71f1019fe7f82c.png

With the keyword: "concurrently" I launch [Script Filter] which launchings the "index.js" and I expect to receive the data of time in "subtitle".

But the file which should be generated with this data of time launchings (concurrently) by the [Run Script] block. in the file "update-concurrently.js" only after the hit [enter] 

Thus I expected to refresh data of time after the [keyword] "concurrently" command. Without [enter]
Is this possible?

So in other words: I want to refresh JSON file by the [keyword]: 'concurrently' - concurrently with the main process of this workflow.

 

For testing Requires - Node.js
p.s. Sorry for my English and for this word - "concurrently" which has been written so many times 😃

Edited by bikeNik
update workflow link

Share this post


Link to post

@vitor

4 hours ago, vitor said:

It should work if you connect the same Keyword to two Run Scripts

 

Doesn't work as I expect: I get two commands instead of one and launch the second script only by the second command.

 

4 hours ago, vitor said:

or if you have both commands in the same Run Script and append a & to the first one, to send the job to the background

In this case, (if I understood correctly) first script (showing time) will be executed after the 5 seconds, that is, after the second script.

Edited by bikeNik

Share this post


Link to post
33 minutes ago, bikeNik said:

In this case, (if I understood correctly) first script (showing time) will be executed after the 5 seconds, that is, after the second script.

 

No. Both scripts will be executed at the same time. Without the &, the second script only executes after the first finishes. With it, the first script starts executing and releases control immediately so the second one can start as well.

Edited by vitor

Share this post


Link to post
7 minutes ago, vitor said:

No. Both scripts will be executed at the same time. Without the &, the second script only executes after the first finishes. With it, the first script starts executing and releases control immediately so the second one can start as well.

Do you mean like that?

218515913_Screenshot2018-12-03at23_04_52.png.627b514001dd60d13e4d7a5c0b64cb49.png

 

I've got 5 seconds delay in this case.. (

Edited by bikeNik

Share this post


Link to post
4 hours ago, bikeNik said:

Do you mean like that?

 

No. The first line needs to read ./node_modules/.bin/run-node index.js "$1" &.

Share this post


Link to post
./node_modules/.bin/run-node index.js "$1" &
./node_modules/.bin/run-node update-concurrently.js "get time"
./node_modules/.bin/run-node update-concurrently.js "get time" &
./node_modules/.bin/run-node index.js "$1"

all these variants that I tried above are returned with a delay in 5 seconds. i.e I get this result

1787551126_Screenshot2018-12-04at09_39_33.png.7ed143f51cd6b3e0a2db383ead11fe15.png

and only after 5 seconds I get this:

615591001_Screenshot2018-12-04at09_39_39.png.d45f4baab3116dcdbfaaa8893691fb1b.png

 

5 seconds in this workflow example is as the imitation of request latency.

Expected that the result with (old) data of time must be is immediate. but the refreshed data of time executed (5 sec) in the background process will be showing in the next time when I invoke this workflow.

 

Share this post


Link to post

strange, I can't understand. I tried asynchronous Javascript functions - async/await in my IDE (VS Code) debug mode. In one file.

And I get result asynchronously as I expect. i.e.

 

{
    "items": [
        {
            "title": "Current time is:",
            "subtitle": " 10:44:35 ",
            "icon": {
                "path": "./time-icon.png"
            },
            "arg": " 10:44:35 "
        }
    ]
}

I get immediately this result in output in my IDE, as expected. And background process (writing JSON file) continues to work. But Alfred showing this result only after All function executed.

 

Why it's happened? 

Is it real to invoke two processes (with Alfred's outputting of his items as first immediately process) asynchronously - in other languages, in bash for example?

Edited by bikeNik

Share this post


Link to post

What exactly are you trying to achieve?

 

You can't have two scripts send results to a Script Filter, AFAIK.

 

Also, Alfred is (or at least was) a bit finicky about what it considers a finished process. Your process must also close STDOUT and STDERR for Alfred to consider it done. So moving processes to the background with & isn't enough. You also have to redirect STDOUT and STDERR, so Alfred doesn't wait for it to complete.

Share this post


Link to post
1 hour ago, deanishe said:

What exactly are you trying to achieve?

 

I want to write JSON file by the network request (this process takes about 5 seconds)  asynchronously with another ONE script sent with the result to a Script Filter. 
In my workflow example, the file "update-concurrently.js" generates JSON file with current time data (like a network request with 5 seconds delay). I want to invoke this file asynchronously (concurrently) with [Script Filter] (where I invoke "index.js" file) 
I would like to get the result of the possibility of this operation.

 

Many thanks, @deanishe I'll try with your suggestions. with STDOUT and STDERR. I'll figure something out...

 

---------------- UPDATE -----------

const items = {
	items: [{
		title: refreshDate.title,
		subtitle: refreshDate.subtitle,
		icon: {path: './time-icon.png'},
		arg: refreshDate.subtitle
	}]
}

const run = async () => {
	await process.stdout.write(JSON.stringify(items)) // to show old data of time from JSON file in Alfred "Script Filter"
	setTimeout(runUpdate, 5000); // delay 5 seconds for gerenerate JSON file with current data of time.
}

run()

got the same 5 seconds latency.

Edited by bikeNik

Share this post


Link to post

Seems I resolved this challenge with the trigger [External]
who would have thought : )

463208672_Screenshot2018-12-04at16_38_12.png.2103ca2bbe0c2229e30ca1d3d256fcaa.png

In Script Filter I invoked AppleScript command:

./node_modules/.bin/run-node index.js '$1'
osascript -e "tell application \"Alfred 3\" to run trigger \"concurrentlyUdate\" in workflow \"org.bikenik.concurrently\""

370653249_Screenshot2018-12-04at16_34_56.png.11af7b0fa884ba887d49936a650b47c8.png

 

Thanks for the support!!

 

p.s. But I'm not sure how many times this AppleScript command will be invoked? Only once, when I type [keyword]?

Edited by bikeNik
added p.s. question

Share this post


Link to post
3 hours ago, bikeNik said:

But I'm not sure how many times this AppleScript command will be invoked? Only once, when I type [keyword]?

 

No. Alfred will try to run the workflow for every single character the user enters (unless "Alfred filters results" is used).

 

As for the concurrency issue:

concurrent.jpg.efe0c8bc3b38c013d88d540331fae8dc.jpg

 

1 and 2 cannot run concurrently because you've connected 2 downstream of 1. That means Alfred won't start 2 until 1 has finished running and the user actions a result.

 

If you want to run two or more elements (Run Script and/or Script Filter) at the same time, they all have to be connected to the same trigger (Hotkey/Snippet Trigger/Keyword etc.)

 

If you want to launch another process in the same script as a Script Filter—and you're not using "Alfred filters results"—you need to have logic in place to ensure it's only run once: as mentioned above, Alfred will typically execute a Script Filter several times as fast as it can, and you could easily end up with 5+ copies of the process running.

Edited by deanishe

Share this post


Link to post
7 hours ago, bikeNik said:

I would like to get the result of the possibility of this operation.

 

So what you want to do is:

 

1. Show something in Alfred, e.g. "fetching data..."

2. Go off to the web and fetch some data

3. Show those data in Alfred

 

Is that right? This whole "concurrency" thing is just the way you think you should do that?

Share this post


Link to post

Right, so if 1 and 2 should start at the same time, either you

  1. Start both via another trigger (Hotkey, Snippet Trigger etc.), or

  2. Start script 2 from the same code as 1, being careful to properly background the process and make sure you're only running one copy of 2 at a time (e.g. using a PID file).

Edited by deanishe

Share this post


Link to post

I remembered that I can invoke AppleScript command from JS file... 
I'll probably leave it at that. And I'm going to read about  PID file.
Thanks again, Deanishe!

Edited by bikeNik

Share this post


Link to post
50 minutes ago, bikeNik said:

I'll probably leave it at that. And I'm going to read about  PID file.

 

If you're launching your long-running script from the Script Filter script, you still have the problem of the script being run multiple times.

 

Unless it's your own server the workflow hammers, you should probably still implement some kind of guard or lock to prevent multiple copies running at the same time.

 

A PID file is just a file that a program creates at a known path when it's running and deletes when it exits. It's called a PID file because the program usually writes its PID to the file, so you can easily check if the program really is running (kill -0 <PID>) or has exited but failed to remove its PID file.

 

Most of my workflows have Script Filters that launch longer-running background jobs to fetch data or check for updates. If you're interested this is the API I wrote for doing that, and here's the demo workflow showing how to use it.

Edited by deanishe

Share this post


Link to post
17 hours ago, deanishe said:

Most of my workflows have Script Filters that launch longer-running background jobs to fetch data or check for updates. If you're interested this is the API I wrote for doing that, and here's the demo workflow showing how to use it.

 

I'm not good enough in NodeJs (apparently) to start learning "GO" language at this moment. But your API ("awgo") is on the first thing that I'll to take for learning GO language. Thanks for the suggestion! 

 

This decision (Nodejs) which I'm taking is: 

if (!alfy.cache.get('start-PID')) {
	alfy.cache.set('start-PID', process.pid, {maxAge: 30000}) // 30 sec.
}

const run = async () => {
	if (alfy.cache.get('start-PID') === process.pid) { // prevent launch for 30 seconds
		await runApplescript(`
		tell application "Alfred 3"
			run trigger ¬
				"concurrentlyUpdate" in workflow ¬
				"org.bikenik.concurrently"
		end tell
		`);
	}
	alfy.output([{
		title: refreshDate.title,
		subtitle: refreshDate.subtitle,
		icon: {path: './time-icon.png'},
		arg: refreshDate.subtitle
	}]);
}
run()

So I limit to running this script at least for 30 seconds. 
Did you do something similar in your script? As I see ... 

I'm going to continue to seek another solution.

Share this post


Link to post

I think that's the wrong PID…

 

By the looks of it, that's the parent script that launches the long-running, background one. You need to save the PID of the long-running, background process and check for it in the parent script. If the PID file doesn't exist or contains an invalid PID, the parent script starts the long-running background process.

 

If you do it the normal way, the parent can write the new process's PID to the PID file. As you're asking Alfred to start the process for you, you can't get its PID, so the background script will have to save its own PID to the PID file.

 

Also, because you're starting the background process asynchronously via Alfred, instead of waiting for it, it's possible Alfred will start running your Script Filter again before it starts the other one, leaving you with multiple copies of the background process running anyway.

Edited by deanishe

Share this post


Link to post
39 minutes ago, deanishe said:

it's possible Alfred will start running your Script Filter again before it starts the other one

I'm acting empirically: And in my example, the data of time change only one time in 30 seconds. So at least, I do know about it to a certain. 

concurrently-test.gif.1c73014babc53561ca67287aa07a3b15.gif

 

Well, I see. it's very valuable information for me. I'll read about it.
Now I know exactly I don't know enough about background processes. Thanks again!

Share this post


Link to post
26 minutes ago, bikeNik said:

I'm acting empirically

 

Yes, you're right. I'd misunderstood what you're script was doing.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×