bikeNik Posted December 3, 2018 Share Posted December 3, 2018 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 So, my question: Is there any way to launch (concurrently) both of these files by ONE command. By [keyword]. Thnx! Link to comment
vitor Posted December 3, 2018 Share Posted December 3, 2018 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. Link to comment
bikeNik Posted December 3, 2018 Author Share Posted December 3, 2018 @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! Link to comment
bikeNik Posted December 3, 2018 Author Share Posted December 3, 2018 (edited) 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]. 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 December 3, 2018 by bikeNik update workflow link Link to comment
bikeNik Posted December 3, 2018 Author Share Posted December 3, 2018 (edited) @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 December 3, 2018 by bikeNik Link to comment
vitor Posted December 3, 2018 Share Posted December 3, 2018 (edited) 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 December 3, 2018 by vitor Link to comment
bikeNik Posted December 3, 2018 Author Share Posted December 3, 2018 (edited) 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? : I've got 5 seconds delay in this case.. ( Edited December 3, 2018 by bikeNik Link to comment
vitor Posted December 4, 2018 Share Posted December 4, 2018 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" &. Link to comment
bikeNik Posted December 4, 2018 Author Share Posted December 4, 2018 ./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 and only after 5 seconds I get this: 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. Link to comment
bikeNik Posted December 4, 2018 Author Share Posted December 4, 2018 (edited) 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 December 4, 2018 by bikeNik Link to comment
deanishe Posted December 4, 2018 Share Posted December 4, 2018 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. Link to comment
bikeNik Posted December 4, 2018 Author Share Posted December 4, 2018 (edited) 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 December 4, 2018 by bikeNik Link to comment
bikeNik Posted December 4, 2018 Author Share Posted December 4, 2018 (edited) Seems I resolved this challenge with the trigger [External]. who would have thought : ) 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\"" 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 December 4, 2018 by bikeNik added p.s. question Link to comment
deanishe Posted December 4, 2018 Share Posted December 4, 2018 (edited) 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: 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 December 4, 2018 by deanishe Link to comment
deanishe Posted December 4, 2018 Share Posted December 4, 2018 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? Link to comment
bikeNik Posted December 4, 2018 Author Share Posted December 4, 2018 (edited) @deanishe Edited December 4, 2018 by bikeNik Link to comment
deanishe Posted December 4, 2018 Share Posted December 4, 2018 (edited) Right, so if 1 and 2 should start at the same time, either you Start both via another trigger (Hotkey, Snippet Trigger etc.), or 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 December 4, 2018 by deanishe Link to comment
bikeNik Posted December 4, 2018 Author Share Posted December 4, 2018 (edited) 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 December 4, 2018 by bikeNik Link to comment
deanishe Posted December 4, 2018 Share Posted December 4, 2018 (edited) 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 December 4, 2018 by deanishe Link to comment
bikeNik Posted December 5, 2018 Author Share Posted December 5, 2018 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. Link to comment
deanishe Posted December 6, 2018 Share Posted December 6, 2018 (edited) 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 December 6, 2018 by deanishe Link to comment
bikeNik Posted December 6, 2018 Author Share Posted December 6, 2018 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. 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! Link to comment
deanishe Posted December 6, 2018 Share Posted December 6, 2018 26 minutes ago, bikeNik said: I'm acting empirically Yes, you're right. I'd misunderstood what you're script was doing. Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now