Reputation: 2077
I have this Go connection snippet in a script:
d := net.Dialer{Timeout: time.Second * 5}
c, err := d.Dial("unix", CONFIG.ServiceSocket.Path)
if err != nil {
handleFatalError(err, errorString)
}
defer c.Close()
// send message
message := fmt.Sprintf("{\"action\":\"%s\"}", *Arguments.Action)
_, err = c.Write([]byte(message))
if err != nil {
var errorString = fmt.Sprintf("Write error: %s", err)
handleFatalError(err, errorString)
}
// read response
buf := make([]byte, CONFIG.ServiceSocket.Buffer)
n, err := c.Read(buf[:])
if err != nil {
var errorString = fmt.Sprintf("Read error: %s", err)
handleFatalError(err, errorString)
}
But the script gets frozen with the following sequence:
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
connect(3, {sa_family=AF_UNIX, sun_path="/var/run/dhcomms/dispatcher.sock"}, 35) = 0
epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=74057432, u64=139805554509528}}) = 0
getsockname(3, {sa_family=AF_UNIX}, [112->2]) = 0
getpeername(3, {sa_family=AF_UNIX, sun_path="/var/run/dhcomms/dispatcher.sock"}, [112->35]) = 0
write(3, "{\"action\":\"status\"}", 19) = 19
read(3, 0xc000100000, 1048576) = -1 EAGAIN (Resource temporarily unavailable)
futex(0x6aafd8, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x6aaed8, FUTEX_WAKE_PRIVATE, 1) = 1
epoll_pwait(4, [{EPOLLOUT, {u32=74057432, u64=139805554509528}}], 128, 0, NULL, 0) = 1
epoll_pwait(4,
I would like to capture this EAGAIN error and close the program in an orderly manner instead.
How should I achieve that ?
EDIT [19/6/23]: Added write/read code
Upvotes: 0
Views: 226
Reputation: 2077
I explain here what I finally did, but I don't like it very much because it seems to me a kind of artificial way to solve the issue. The program get blocked reading the socket:
n, err = c.Read(buf[:])
So I wrap it inside a go routine with a channel an apply a timeout to the whole thing:
var TIMEOUT_READ_SOCKET_UNIX time.Duration = 5
buf := make([]byte, CONFIG.ServiceSocket.Buffer)
c1 := make(chan string, 1)
var n int
go func() {
n, err = c.Read(buf[:])
c1 <- ""
}()
select {
case res := <-c1:
fmt.Println(res)
break
case <-time.After(TIMEOUT_READ_SOCKET_UNIX * time.Second):
var errorString = "Timeout reading unix socket"
err := fmt.Errorf("Timeout = %d seconds", TIMEOUT_READ_SOCKET_UNIX)
handleFatalError(err, errorString)
}
I didn't find the way to apply a timeout to the unix socket when the EAGAIN error happens. I bet this should be the right way. If someone knows how to do that, please...
NOTE: I used go-version 1.20 and I'm newby in Go.
Upvotes: -1