Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
tim_beynart
Level 7

Best way to fire several http requests?

I have to fire off ad beacons from an SG app at specific points in a stream.  In practice this means I can have over a dozen HTTP calls at once. I do not care about the responses.
Right now I have a task to handle the HTTP requests, and I create a new task for each request.
However I ran into a problem that plagued me in SDK1, where the task is garbage collected before the HTTP request is made.
To get around this I append the tasks to a list, then every now and then trim the list of completed requests. This feels like a kludge. Is there a best practice for spinning up a task and keeping it around until it completes, and only then allowing it to be garbage collected?

Here's the task code:
Sub dorequest()
    url = m.top.url
    ? "[HTTP Request] ", url
    request = createobject("roUrlTransfer")
    port = createobject("roMessagePort")
    msgfailurereason="n/a"
    msgcode="n/a"
    request.setmessageport(port)
    request.setcertificatesfile("common:/certs/ca-bundle.crt")
    request.initclientcertificates()
    request.enablehostverification(false)
    request.enablepeerverification(false)
    request.retainbodyonerror(true)
    request.seturl(url)

    if (request.asyncgettostring())
      while (true)
        msg = wait(5000, port)
        if (type(msg) = "roUrlEvent")
          if (msg.getresponsecode() > 0 OR msg.getresponsecode() < 400)
            ? "[HTTP Request] SUCCESS. ",msg.getresponsecode()
          else
            msgfailureresponse = msg.getstring()
            if msg.getresponsecode() <> invalid
              msgcode = msg.getresponsecode()
            end if
            if msg.getfailurereason() <> invalid
              msgfailurereason = msg.getfailurereason()
            end if
            ? "[HTTP Request] REQUEST FAILED: ",url
            ? "[HTTP Request] CODE: ",msgcode, "REASON: ",msgfailurereason
          end if
          request.asynccancel()
          exit while
        else if (msg = invalid)
          ? "[HTTP Request] BEACON REQUEST FAILED: ",url
          request.asynccancel()
        end if
      end while
    end if
    m.top.complete=true
End Sub


Here's my first stab at the code that uses it:

Sub fireBeacon(url as String)
    ? "Fire Beacon. ", url
    task = CreateObject("roSGNode", "http_request")
    task.url = url
    task.control = "RUN"
    'keep task from getting garbage collected
    m.http_tasks.AddReplace(url,task)
    cleanup_requests()
End Sub

sub cleanup_requests()
  ? "m.http_tasks 1: ",m.http_tasks.count()
  for each t in m.http_tasks
    ? m.http_tasks[t].state
    if m.http_tasks[t].complete
      m.http_tasks.delete(t)
    end if
  end for
  ? "m.http_tasks 2: ",m.http_tasks.count()
end sub
0 Kudos
8 Replies
destruk
Level 10

Re: Best way to fire several http requests?

If you have 12 calls, you might consider having 12 discrete individual task nodes.  That way you have enough time for each to complete before needing to launch another volley.
0 Kudos
tim_beynart
Level 7

Re: Best way to fire several http requests?

I thought I was creating a discrete task node for each call using CreateObject("roSGNode", "http_request") ?
The number of calls can vary, there can be anywhere from 2 to 30 for an event.
EDIT:
The issue is that "task" is a local variable for that function, so once the function returns it gets nuked. I was hoping task nodes, once spawned, stayed alive until they finished.
0 Kudos
tim_beynart
Level 7

Re: Best way to fire several http requests?

I guess another approach is to write a queue and fire off the requests in series.
0 Kudos
destruk
Level 10

Re: Best way to fire several http requests?

That is what they say (a task node spawns a new process).  I have noticed with event observers if you have an always notify on change callback set, as soon as it changes at all the callback is executed.  This means when you get a string from a server you need to wait for the entire string to be received before setting the field to it.  But then perhaps I was just doing it wrong - when I changed to storing it as a variable first and then setting the field to the variable value it worked better for me.
0 Kudos
Roku Employee
Roku Employee

Re: Best way to fire several http requests?

"tim_beynart" wrote:
I guess another approach is to write a queue and fire off the requests in series.

The real question is why are you re-inventing the wheel?
RAF already has a facility for firing beacons automatically - or you can do it manually by calling raf.fireTrackingEvents()
That code is solid and vetted in production, can handle hundreds of beacons simultaneously in an app (and does handle many millions per day). It's a non-blocking call, takes care handling async requests behind the scenes and avoids the "nuclear option". Do you have special needs it can't cover?
0 Kudos
tim_beynart
Level 7

Re: Best way to fire several http requests?

We aren't using RAF.
0 Kudos
tim_beynart
Level 7

Re: Best way to fire several http requests?

I guess I should have made my real question more clear:
Are tasks kept in memory until they complete?
My experience tells me "no", since my generated task stops logging as soon as the function that created it returns. So the next question is, what is a clean technique for running tasks in the background without babysitting the garbage collector?
0 Kudos
Roku Employee
Roku Employee

Re: Best way to fire several http requests?

"tim_beynart" wrote:
We aren't using RAF.

That's rather unfortunate then  8-)
0 Kudos