dial tcp i/o timeout with HTTP GET request - go

Running into some error, I must be overlooking something.
How can I debug this? Dropping connections?
I read the following:
golang - Why net.DialTimeout get timeout half of the time?
Go. Get error i/o timeout in server program
golang get massive read tcp ip:port i/o timeout in ubuntu 14.04 LTS
Locating the "read tcp" error in the Go source code
Getting sporadic "http: proxy error: read tcp: i/o timeout" on Heroku
Error created here:
https://github.com/golang/go/blob/b115207baf6c2decc3820ada4574ef4e5ad940ec/src/net/net.go#L179
Goal:
Send a Get request to a url.
Expected result:
return body in JSON.
Encountered problem:
I/O timeout
It works in Postman
Edit:
I added a modified timeout...
Edit2: traced error
Postman request:
GET /v2/XRP-EUR/candles?interval=1h HTTP/1.1
Host: api.bitvavo.com
Postman Result (1440 rows):
[
[
1609632000000,
"0.17795",
"0.17795",
"0.17541",
"0.17592",
"199399.874013"
],
[
1609628400000,
"0.17937",
"0.18006",
"0.17622",
"0.17852",
"599402.631894"
],
[
1609624800000,
"0.18167",
"0.18167",
"0.17724",
"0.17984",
"579217.962574"
],.....
Code:
package main
import (
"fmt"
"net/http"
"io/ioutil"
"time"
)
func main() {
url := "https://api.bitvavo.com/v2/XRP-EUR/candles?interval=1h"
method := "GET"
client := &http.Client {
}
client.Timeout = time.Second * 60
req, err := http.NewRequest(method, url, nil)
if err != nil {
fmt.Println(err)
return
}
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
result:
Get "https://api.bitvavo.com/v2/XRP-EUR/candles?interval=1h": dial tcp 65.9.73.10:443: i/o timeout

I was with this issue when building inside docker containers.
Not sure why, but after a docker swarm leave --force and a systemctl restart docker the build worked.

Local environment, firewall not allowing golang to dial tcp..
It still allowed the url to be resolved to an ip though (DNS)
Solution:
Change firewall settings locally,
Check Docker/kubernetes/reverse proxy settings

Related

Memcached Ping() doesn't return an error on an invalid server

I use memcache for caching and the client I use is https://github.com/bradfitz/gomemcache. When I tried initiate new client with dummy/invalid server address and then pinging to it, it return no error.
package main
import (
"fmt"
m "github.com/bradfitz/gomemcache"
)
func main() {
o := m.New("dummy_adress")
fmt.Println(o.Ping()) // return no error
}
I think it suppose to return error as the server is invalid. What do I miss?
It looks like the New() call ignores the return value for SetServers:
func New(server ...string) *Client {
ss := new(ServerList)
ss.SetServers(server...)
return NewFromSelector(ss)
}
The SetServers() function will only set the server list to valid servers (in
your case: no servers) and the Ping() funtion will only ping servers that are
set, and since there are no servers set it doesn't really do anything.
This is arguably a feature; if you have 4 servers and one is down then that's
not really an issue. Even with just 1 server memcache is generally optional.
You can duplicate the New() logic with an error check:
ss := new(memcache.ServerList)
err := ss.SetServers("example.localhost:11211")
if err != nil {
panic(err)
}
c := memcache.NewFromSelector(ss)
err = c.Ping()
if err != nil {
panic(err)
}
Which gives:
panic: dial tcp 127.0.0.1:11211: connect: connection refused

Connections stuck at CLOSE_WAIT in golang server

I am using gorilla mux to create a golang server to support a simple health GET endpoint.
The endpoint responds with a status of ok whenver the server is up.
I see a lot of connections (over 400) in CLOSE_WAIT state on one system.
This does not happen on other systems with the same code.
Output of netstat (9003 is my server port):
tcp 164 0 ::1:9003 ::1:60702 CLOSE_WAIT -
tcp 164 0 ::1:9003 ::1:44472 CLOSE_WAIT -
tcp 164 0 ::1:9003 ::1:31504 CLOSE_WAIT -
This seems to imply that I have a connection I need to close.
Most of the questions I read online seem to suggest that open connections pertain to the client not issuing a response.body.close() after a GET.
As per https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/, I could add read/write timeouts on server side but I would like to understand the root cause of CLOSE_WAITS before adding the improvements.
Am I missing any close on the server side?
My code is below:
import "github.com/gorilla/mux"
...
func (server *Srvr) healthHandler(w http.ResponseWriter, r *http.Request) {
resp := map[string]string{"status": "ok"}
respJSON, err := json.Marshal(resp)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Error creating JSON response %s", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(respJSON)
}
// Load initializes the servers
func Load(port string) *Srvr {
srvrPort := ":" + port
log.Infof("Will listen on port %s", srvrPort)
serverMux := mux.NewRouter()
srvr := &Srvr{Port: port, Srv: &http.Server{Addr: srvrPort, Handler: serverMux}}
serverMux.HandleFunc("/api/v1.0/health", srvr.healthHandler).Methods("GET")
return srvr
}
// Run starts the server
func (server *Srvr) Run() {
log.Info("Starting the server")
// Starting a server this way to allow for shutdown.
// https://stackoverflow.com/questions/39320025/how-to-stop-http-listenandserve
err := server.Srv.ListenAndServe()
if err != http.ErrServerClosed {
log.Fatalf("ListenAndServe(): %s", err)
}
}
// Main resides outside the server package
func main() {
srvr := server.Load("9003")
// Now that all setup is done successfully, lets start the server
go srvr.Run()
// An unrelated forever loop executes below for different business logic
for {
glog.Info("Evaluation iteration begins now")
...
time.Sleep(time.Duration(evalFreq) * time.Minute)
}
}

Unable to connect with HTTP proxy

go version: go1.13.5 linux/amd64
I am using "x/net/proxy" to connect with the "http_proxy".
I have referred following proxy page:
https://godoc.org/golang.org/x/net/proxy
To get proxy information I have set environment variable "all_proxy" to the the desired proxy "http://192.130.0.10:3200", and performed the tcp connection, but following error is raised:
[Network Error : socks connect tcp 192.130.0.10:3200->mx.eu1.mico.io:8883: read tcp 172.17.0.2:48118->192.130.0.10:3200: read: connection reset by peer]
I have looked "x/net/proxy", It seems "http_proxy" support is not available instead of "SOCKS5" proxy is supported. I have similar implementation for "http_proxy", but unfortunately it does not worked.
I have created a sample code (with port 1883) which is working for the non proxy environment, Please suggest how I can enable "http_proxy" or "https_proxy" support?
package main
import (
"fmt"
"os"
"golang.org/x/net/proxy"
)
//The host address which we want to connect with the proxy
var host = "google.com:80"
func main() {
fmt.Println("Inside main...")
//Setting the proxy before starting the application
if os.Getenv("http_proxy") == "" {
os.Setenv("http_proxy", "http://192.130.0.10:3200")
}
os.Setenv("all_proxy", os.Getenv("http_proxy"))
if os.Getenv("all_proxy") != os.Getenv("http_proxy") {
fmt.Println("Environment variables are not matching...")
return
}
fmt.Println("System proxy is:", os.Getenv("all_proxy"))
proxyDialer := proxy.FromEnvironment()
fmt.Println("Connecting to...", host)
conn, err := proxyDialer.Dial("tcp", host)
if err != nil {
fmt.Println("Unable to dial...", err)
return
}
fmt.Println("Connected...", conn)
}
Output:
Inside main...
System proxy is: http://192.130.0.10:3200
Connecting to... google.com:80
Unable to dial... dial tcp 172.217.23.174:80: connect: connection timed out
What's your purpose?
If you need to use an http-proxy server for http requests, you can just configure your http-client without another package usage:
package main
import (
"fmt"
"net/http"
"net/url"
"time"
)
func main() {
proxyUrl, err := url.Parse("http://192.130.0.10:3200")
if err != nil {
// TODO handle me
panic(err)
}
cl := http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyUrl),
},
Timeout: 3000 * time.Millisecond,
}
resp, err := cl.Get("http://google.com")
if err != nil {
// TODO handle me
panic(err)
}
// TODO work with the response
fmt.Println(resp)
}

Open URL on open port

I'm assuming I can run a service on port 3000 like many other code samples I've seen on Github.
Now I am trying to improve my code so that it looks for an open port in case 3000 is in use:
for port := 3000; port <= 3005; port++ {
fmt.Println(port)
err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
if err == nil {
fmt.Println("lk is serving", dirPath, "from http://0.0.0.0:", string(port))
open.Start("http://0.0.0.0:" + string(port))
}
}
However it blocks on the http.ListenAndServe line and doesn't open.Start my browser. I'm told I should use goroutines but I am still a bit bewildered how to use them in this context.
This is a "client" Web app so I do need it to invoke my browser.
Instead of calling ListenAndServe, create the Listener in the application and then call Serve. When creating the listener, request a free port by specifying the listener address as ":0":
ln, err := net.Listen("tcp", ":0")
if err != nil {
// handle error
}
Once the listener is open, you can start the browser:
open.Start("http://" + ln.Addr().String())
and then start the server:
if err := http.Serve(ln, nil); err != nil {
// handle error
}
There's no need to use a goroutine.
The code above uses addr.String() to format the listener's address. If you do need to get the port number for some reason, use a type assertion:
if a, ok := ln.Addr().(*net.TCPAddr); ok {
fmt.Println("port", a.Port)
}

Redis instance missing cache often using go-lang client redigo

I'm developing an api for blog or online publishing website to develop a recommendation engine for their content.
Since my api returns same json for same url request, I decided to use Redis as a cache for high traffic websites by passing the url as key and json as value. I am developing this api in go-lang recently and have been using redigo to talk to our Redis instance. The way I decided to architect my system is to check the url of the query sent by the client (blog) and search for it in redis. If however, the url response in not cached I do a 301 redirect to another api that applied the logic to generate the json response for that particular url and also set the redis cache. However, while I'm testing if my Redis is working properly, I realised that it is missing cache far too often than what I would like. It's definitely caching the json response mapped to the url as confirmed by doing a simple GET in Redis-cli but after 3-4 hits I could see Redis missing cache again. I'm still very new to go-lang and caching world so I'm not sure if I'm missing something in my implementation. Also, I would like to know under what circumstances can Redis instance miss caches ? It can't be timeout because Redis docs says "By default recent versions of Redis don't close the connection with the client if the client is idle for many seconds: the connection will remain open forever." so I'm not sure what exactly is happening with my setup. Relevant part of my code is below:
package main
import (
"flag"
"fmt"
"github.com/garyburd/redigo/redis"
"log"
"net/http"
"time"
)
var (
port int
folder string
pool *redis.Pool
redisServer = flag.String("redisServer", "redisip:22121", "")
redisPassword = flag.String("redisPassword", "", "")
)
func init() {
flag.IntVar(&port, "port", 80, "HTTP Server Port")
flag.StringVar(&folder, "folder", "www", "Serve this folder")
}
func newPool(server, password string) *redis.Pool {
return &redis.Pool{
MaxIdle: 3,
MaxActive: 25000,
IdleTimeout: 30 * time.Second,
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", server)
if err != nil {
return nil, err
}
return c, err
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
_, err := c.Do("PING")
return err
},
}
}
func main() {
flag.Parse()
pool = newPool(*redisServer, *redisPassword)
httpAddr := fmt.Sprintf(":%v", port)
log.Printf("Listening to %v", httpAddr)
http.HandleFunc("/api", api)
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(folder))))
log.Fatal(http.ListenAndServe(httpAddr, nil))
}
func api(w http.ResponseWriter, r *http.Request) {
link := r.URL.Query().Get("url")
fmt.Println(link)
heading := r.URL.Query().Get("heading")
conn := pool.Get()
reply, err := redis.String(conn.Do("GET", link))
defer conn.Close()
if err != nil {
fmt.Println("Error for link %v:%v", heading, err)
http.Redirect(w, r, "json-producing-api", 301)
}
fmt.Fprint(w, reply)
}
I must also mention here that in the above code, my redis instance is actually a twemproxy client built by twitter which proxies three different redis client running behind on three different ports. Everything seemed to worked normal yesterday and I did a successful load test for 5k concurrent reuquests. However, when I checked the log today some queries were being missed by redis and were being redirected to my json-producing-api and I could see redigo:nil error. I'm totally confused as to what exactly is going wrong? Any help will be greatly appreciated.
EDIT: As per discussions below, I'm detailing the code that I use to set the data in Redis
func SetIntoRedis(key string, value string) bool {
// returns true if successfully set, returns false in case of an error
conn := pool.Get()
_, err := conn.Do("SET", key, value)
if err != nil {
log.Printf("Error Setting %v : %v", key, err)
return false
}
return true
}
Configuration of my twemproxy client
leaf:
listen: 0.0.0.0:22121
hash: fnv1a_64
distribution: ketama
redis: true
auto_eject_hosts: true
server_retry_timeout: 3000
server_failure_limit: 3
servers:
- 127.0.0.1:6379:1
- 127.0.0.1:6380:1
- 127.0.0.1:6381:1

Resources