lua http socket timeout
Asked Answered
S

2

11

The LuaSocket HTTP module documentation says that a timeout can be set on a HTTP connection:

The following constants can be set to control the default behavior of the HTTP module:

PORT: default port used for connections; PROXY: default proxy used for connections; TIMEOUT: sets the timeout for all I/O operations; USERAGENT: default user agent reported to server. http://w3.impa.br/~diego/software/luasocket/http.htm

How do I set these constants in a lua script?

Sizar answered 16/5, 2011 at 10:31 Comment(4)
Add your solution as an answer and accept it, so this question would be complete.Applique
I tried but I have to wait 8 hours after the time of the first post before I can answer to my own question. I will do it this evening (CET).Sizar
That restriction should be gone now that you have over 10 rep points.Tortoiseshell
Nope. I still have thet same notice: New users can't answer their own question for 8 hours. Please use comments, or edit your question instead.Sizar
E
14

You can do this to set a timeout for one request instead of the entire HTTP module:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  req_sock:settimeout(5)
  return req_sock
end}

Note that the default behavior of :settimeout, as well as global settings like http.TIMEOUT, sets a time limit for any individual operation within the request - in other words, it's how long the operation may go without any activity before timing out. If you wish to set an overall upper bound on an operation - a time that the overall request can't exceed, regardless of activity - you should pass a mode argument of 't' as the second parameter to :settimeout, like so:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  -- note the second parameter here
  req_sock:settimeout(5, 't')
  return req_sock
end}

As an example to illustrate the distinction between the two modes, imagine that, after making your request, the server responded with a chunk of the response once a second, taking seven seconds overall to complete. With req_sock:settimeout(5, 'b') (or just req_sock:settimeout(5)) setting a 5-second block timeout, this request would proceed just fine, as none of the underlying I/O operations took longer than five seconds: however, with req_sock:settimeout(5, 't') setting a five-second total timeout, the request would fail after five seconds.

Of course, it may make sense to set restrictions for both of these durations, having both a short inactivity timeout as well as a longer overall timeout. As such, per the documentation, you can make two separate calls to specify both:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  req_sock:settimeout(5, 'b')
  req_sock:settimeout(30, 't')
  return req_sock
end}
Eliezer answered 16/5, 2011 at 18:35 Comment(8)
I am not sure I understand this. With the solution I found (posted below now), do I really change the timeout for all new HTTP sockets? If that is the case, I could reset its value to the default 60 seconds after the connection succeeded. Can you explain on your snippet, especially the create = function() part?Sizar
I just made some test and, indeed, when I change the timeout with mysocket.TIMEOUT it keeps that value for all new HTTP sockets created afterwards unless you change it again. With your suggestion don't you create two sockets? One http and one tcp?Sizar
@Sizar The create parameter of the request specifies the function to create the TCP socket it uses to perform the HTTP request (the HTTP Application layer going over the TCP Transport layer). If you don't specify a create function, http.request will use a plain call to tcp() by default (see the manual).Eliezer
Oh, I see. Although setting the default value for the entire module for the duration of the script is usually not a problem, your solution offers better control on the HTTP socket. Thanks Stuart.Sizar
Line 2 require "socket.tcp" and Line 4 local socket = tcp() are invalid. Line 2 should be deleted and Line 4 should be local socket = socket.tcp().Nosology
I got better results with req_sock:settimeout(2,'t'). The 't' is a mode that specifies that the timeout... well, idk. But it worksGley
FYI, stack overflow (in my case) hid the last two comments (which are important). Can you change the line to req_sock:settimeout(5,'t') which will set the total timeout. The default 'block' timeout is not intuitive and doesn't behave the same as the similar "http.TIMEOUT=5" cases mentioned throughout answers to the question.Albania
As far as I can tell from the documentation, the "block" timeout mode does behave the same way as http.TIMEOUT - both control the timeout time for each I/O operation. I've added an explanation about timeout modes to the answer, but I'm sticking to the default in the initial section describing the alternative to http.TIMEOUT.Eliezer
S
15

It was easier than I thought. simply

local mysocket = require("socket.http")
mysocket.TIMEOUT = 5
Sizar answered 16/5, 2011 at 18:48 Comment(2)
does this have 'side effects', changing http socket configurations outside of the file that does the require ? (i.e. code on the same program but on another file that does its own require for http.socket)Gley
@josinalvo: Yes, all files within a program share the same instances of their common modules under package.loaded. See my answer for a way to do this without side effects.Eliezer
E
14

You can do this to set a timeout for one request instead of the entire HTTP module:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  req_sock:settimeout(5)
  return req_sock
end}

Note that the default behavior of :settimeout, as well as global settings like http.TIMEOUT, sets a time limit for any individual operation within the request - in other words, it's how long the operation may go without any activity before timing out. If you wish to set an overall upper bound on an operation - a time that the overall request can't exceed, regardless of activity - you should pass a mode argument of 't' as the second parameter to :settimeout, like so:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  -- note the second parameter here
  req_sock:settimeout(5, 't')
  return req_sock
end}

As an example to illustrate the distinction between the two modes, imagine that, after making your request, the server responded with a chunk of the response once a second, taking seven seconds overall to complete. With req_sock:settimeout(5, 'b') (or just req_sock:settimeout(5)) setting a 5-second block timeout, this request would proceed just fine, as none of the underlying I/O operations took longer than five seconds: however, with req_sock:settimeout(5, 't') setting a five-second total timeout, the request would fail after five seconds.

Of course, it may make sense to set restrictions for both of these durations, having both a short inactivity timeout as well as a longer overall timeout. As such, per the documentation, you can make two separate calls to specify both:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  req_sock:settimeout(5, 'b')
  req_sock:settimeout(30, 't')
  return req_sock
end}
Eliezer answered 16/5, 2011 at 18:35 Comment(8)
I am not sure I understand this. With the solution I found (posted below now), do I really change the timeout for all new HTTP sockets? If that is the case, I could reset its value to the default 60 seconds after the connection succeeded. Can you explain on your snippet, especially the create = function() part?Sizar
I just made some test and, indeed, when I change the timeout with mysocket.TIMEOUT it keeps that value for all new HTTP sockets created afterwards unless you change it again. With your suggestion don't you create two sockets? One http and one tcp?Sizar
@Sizar The create parameter of the request specifies the function to create the TCP socket it uses to perform the HTTP request (the HTTP Application layer going over the TCP Transport layer). If you don't specify a create function, http.request will use a plain call to tcp() by default (see the manual).Eliezer
Oh, I see. Although setting the default value for the entire module for the duration of the script is usually not a problem, your solution offers better control on the HTTP socket. Thanks Stuart.Sizar
Line 2 require "socket.tcp" and Line 4 local socket = tcp() are invalid. Line 2 should be deleted and Line 4 should be local socket = socket.tcp().Nosology
I got better results with req_sock:settimeout(2,'t'). The 't' is a mode that specifies that the timeout... well, idk. But it worksGley
FYI, stack overflow (in my case) hid the last two comments (which are important). Can you change the line to req_sock:settimeout(5,'t') which will set the total timeout. The default 'block' timeout is not intuitive and doesn't behave the same as the similar "http.TIMEOUT=5" cases mentioned throughout answers to the question.Albania
As far as I can tell from the documentation, the "block" timeout mode does behave the same way as http.TIMEOUT - both control the timeout time for each I/O operation. I've added an explanation about timeout modes to the answer, but I'm sticking to the default in the initial section describing the alternative to http.TIMEOUT.Eliezer

© 2022 - 2024 — McMap. All rights reserved.