say i receive a POST request from user, after saving to DB, i want to send text messages (via twilio) to some numbers
the response to the user is delayed till the messages are sent
however when i tried to use threads i got the error
toolchains/nim-1.6.10/lib/pure/asyncmacro.nim(200, 31) Error: 'myrouterIter' is not GC-safe as it accesses 'rdb' which is a global using GC'ed memory
rdb here is nim-allographer instance
if i try to make the proc that sends text messages as {. async .} it still blocks
i am looking for some help in making the text proc run in background while the user immediately receives the response
Thank you
Hm it's a bit hard to tell what you've tried,
but i guess you could try to create that thread with the rdb.
Third parameter on the createThread. This should avoid the gc-safe error.
Than use a channel to pass the messages to the the thread.
What is in your sendText() proc? Do you call it with asyncCheck sendText()?
What @gs suggest, or go further and create a microservice where you can pass the info to through e.g. redis.
If it's okay that the blocking persist after the user received the response, then you can use jesters after:
post "/send/text":
resp "Thanks, sending now"
after "/send/text":
sendingText()
both /after and asyncCheck blocks the response back to client, for the timebeing i am using redis to dispatch the job to another nim program to send the actual message
will take sometime to really understand the async flow in the coming weeks
Thanks
I'd like to piggyback on this question and ask another one. Is there a way to pass a value from the get handler to the corresponding after handler without using global variables? If I do it like in the following pseudocode, I cannot compile because the after handler cannot see random_number
get "/roll-a-dice":
let random_number = random(1..6)
resp $random_number
after "/roll-a-dice":
logger.log(lvlInfo, "The dice roll was" & $random_number)
I just checked jester's docs. The result variable type is
ResponseData* = tuple[
action: CallbackAction,
code: HttpCode,
headers: ResponseHeaders,
content: string,
matched: bool
]
Hi Cnerd, Thank you for your comment. It worked with the code like this:
get "/roll-a-dice":
let random_number = rand(1..6)
if result.headers.isNone():
result.headers = some(RawHeaders(@[]))
result.headers.get().add((key: "x-random", val: $random_number))
resp $random_number
after "/roll-a-dice":
{.gcsafe.}:
if result.headers.isSome():
for header in result.headers.get():
if header.key == "x-random":
logger.log(lvlInfo, "The dice roll was " & $header.val)
Background tasks are an issue for any web-based service.
I don't think using a thread would be a good idea even if you could figure out howto get it to work. There's likely some timeout threshold you'd encounter. Either in nginx or whatever server you're using.
In my Ruby Sinatra/Rails days, I used to use delayed_job which would use a database to serialize the job code. There was also a daemon running which would poll the database and run the jobs. Sidekiq was another popular option for Rails. It uses redis instead of a database.
If you're hosting this in the cloud, another option is to move your job logic to a cloud function or cloud run job and trigger it from your web service via publishing a message/data to a pub/sub topic. Your cloud function can be triggered by the pub/sub, or your cloud run job can be scheduled and it can pull from the pub/sub.
Those are the models I use now in most of my projects.