Press any key in 5 seconds - events

To clarify, I am using ComputerCraft (emulator: http://gravlann.github.io/, language: Lua)
I know that to wait for a keypress
os.pullEvent("key")
and to wait 5 seconds I need to use this
sleep(5)
but I want to wait for a keypress and disable the event waiter after 5 seconds.

I'm not familiar with ComputerCraft API, but I guess, You could use parallel API for this. Basically, it allows executing two or more functions in parallel.
To be specific - parallel.waitForAny. Which returns after any of function finished, so, only the one being executed. In contrary, parallel.waitForAll waits for all functions being executed.
I'd use something like this:
local action_done = 0
local function wait_for_keypress()
local event, key_code = os.pullEvent("key")
--do something according to separate key codes? :}
end
local function wait_some_time()
sleep(5)
end
action_done = parallel.waitForAny(wait_for_keypress, wait_some_time)
--action done now contains the number of function which was finished first.
EDIT: if using only ComputerCraft API, You should change to this (using timer event):
local function wait_some_time()
os.startTimer(5)
end

Related

Why am I not allowed to break a Promise?

The following simple Promise is vowed and I am not allowed to break it.
my $my_promise = start {
loop {} # or sleep x;
'promise response'
}
say 'status : ', $my_promise.status; # status : Planned
$my_promise.break('promise broke'); # Access denied to keep/break this Promise; already vowed
# in block <unit> at xxx line xxx
Why is that?
Because the Promise is vowed, you cannot change it: only something that actually has the vow, can break the Promise. That is the intent of the vow functionality.
What are you trying to achieve by breaking the promise as you showed? Is it to stop the work being done inside of the start block? Breaking the Promise would not do that. And the vow mechanism was explicitly added to prevent you from thinking it can somehow stop the work inside a start block.
If you want work inside a start block to be interruptible, you will need to add some kind of semaphore that is regularly checked, for instance:
my int $running = 1;
my $my_promise = start {
while $running {
# do stuff
}
$running
}
# do other stuff
$running = 0;
await $my_promise;
Hope this made sense.
The reason why you cannot directly keep/break Promise from outside or stop it on Thread Pool are explained here in Jonathans comment.
Common misuse of Promises comes from timeout pattern.
await Promise.anyof(
start { sleep 4; say "finished"; },
Promise.in( 1 )
);
say "moving on...";
sleep;
This will print "finished". And when user realize that the next logical step for him is to try to kill obsolete Promise. While the only correct way to solve it is to make Promise aware that its work is no longer needed. For example through periodically checking some shared variable.
Things gets complicated if you have blocking code on Promise (for example database query) that runs for too long and you want to terminate it from main thread. That is not doable on Promises. All you can do is to ensure Promise will run in finite time (for example on MySQL by setting MAX_EXECUTION_TIME before running query). And then you have choice:
You can grind your teeth and patiently wait for Promise to finish. For example if you really must disconnect database in main thread.
Or you can move on immediately and allow "abandoned" Promise to finish on its own, without ever receiving its result. In this case you should control how many of those Promises can stack up in background by using Semaphore or running them on dedicated ThreadPoolScheduler.

tarantool how to handle lua errors outside the fiber

I am wondering, how can i set callback on fiber error throw.
example:
local fiber = require("fiber")
local status = 0 --in my case stored in db
local function time_consuming()
lua_error
status = 0
end
function external_api_function()
if status == 1 then return "already running" end
status = 1
fiber.create(time_consuming)
return "started"
end
so i want to set status to 0 if time_consuming function falls. Is where any way to catch it?
I think about checking fiber:status on next api visit. Or create a watchdog for fiber, if i want status to be valid. This will work for me, but seems like not the best solution.
There are multiple ways to achieve your goal.
Within your example both fibers (main and time_consuming task) share the same scope - status variable. If you change the value of the status variable in the child fiber, parent fiber will see an update. You can check this using simple snippet:
status = 1
fiber.create(function() status = 0 end)
print(status) -- 0
Now, to catch an exception, use pcall function. It accepts a function as a first argument, calls it and returns status as a first value following one or more function results. There is also xpcall function if you want to analyse the error being caught. It takes error handler as a second argument.
With pcall you may change your time_consuming function like this:
local function time_consuming()
local ok = pcall(function() lua_error end)
if not ok then
status = 0
end
end
and status will successfully updated if lua_error fails.
But usually I consider this as a bad practice. If more fibers share the same state, it may become difficult to maintain due to uncertainty of the order of fiber execution. So for more reliable solution you may want to use interfiber communication primitives aka channels. You will be able to explicitly ask child fiber to tell you its execution status whether it succeed or not using channel:put() and channel:get() function. See documentation for examples.

Call EventMachine defer within callback?

I'm using EventMachine.defer to handle some long-running processes (an indefinite wait for a response from an outside application). I want to do this in a loop: each time the application responds, I process the response and then immediately want to start waiting for the next response.
My code currently looks like this:
def watch_for_songs_change
EM.defer(
->( ){ `mpc idle playlist` }, # wait for the song list to change
->(_){ update_songs; watch_for_songs_change }
)
end
I realized that this is calling defer from within a callback from defer. Is this valid? Am I spawning one thread from inside another, and will eventually run out of threads? Or does EventMachine invoke the callback after it has returned the thread to the pool?
I've tried to chain calls like this before in EM, and found that using periodic timers is a usually a better design.
#timer = EventMachine.add_periodic_timer( 1 ) { `mpc idle playlist` and update_songs }

Possible to run ActiveRecord "each" block inside EventMachine periodic timer without blocking?

I'd like to perform a batch database query for a large data set using ActiveRecord inside EventMachine. I'd like each call of the block passed to find_each to be called within an EventMachine periodic timer.
With the following, the find_each simply runs, and the add_periodic_timer block only runs once until the find_each is completely finished (i.e. the periodic timer block doesn't run every 0.001 seconds):
EventMachine.add_periodic_timer(0.001) do
TradingCore::Quote.by_date(#date).by_symbols(#symbols).order(:created_at).find_each do |quote|
...
sleep(delay)
end
end
Is there any way to make the find_each block execute for each record without blocking the event loop?
Think I solved this using a fiber. So, I did this
quotes_fiber = Fiber.new {
TradingCore::Quote.by_date(#date).by_symbols(#symbols).order(:created_at).find_each do |quote|
...
sleep(delay)
Fiber.yield
end
}
EventMachine.add_periodic_timer(0.001) do
quotes_fiber.resume
end
and things seem to work fine :)

What is the best way to periodically export a counter from a loop in Ruby

I have created a daemon in Ruby which has a counter incrementing inside of a loop. The loop does its business, then sleeps for 1 second, then continues. Simplified it's something like:
loop do
response = send_command
if response == 1
counter += 1
end
sleep(1)
end
Every 5 minutes I would like to call a method to database the counter value. I figure there are a few ways to do this. The initial way I considered was calling Time.now in the loop, examining it to match 5 minutes, 0 seconds, and if that matched, call the sql function. That seems terribly inefficient, however, and it could also miss a record if send_command took some time.
Another possibility may be to make available the counter variable, which could be called (and reset) via a socket. I briefly took a look at the Socket class, and that seems possible.
Is there an obvious/best way to do this that I'm missing?
If you just want to save every 5 minutes, you could just use a Thread. Something like:
Thread.new do
save_value_in_the_db(counter)
sleep 5*60
end
Note that the thread have access to counter if it is defined in the same block as the loop. you could also use an object and have the #counter declared insidd.
If you prefer to access remotely, you can do it with a socket or use a drb approach, that is probably easier. This drb tutorial seem to fit your requirements: http://ruby.about.com/od/advancedruby/a/drb.htm
I'd have the counter be updated every time through the loop, then periodically have something read that and update the database.
That makes a simpler main loop because it doesn't have to pay attention to how long it's needed to wait before exporting the value.
And, it's very common and normal to have a periodic task that samples a value and does something with it.
Creating a simple socket would work well. Ruby's Socket code RDoc has some samples for echo servers that might get you started.

Resources