23 days ago
My API is written in GO and I have ensured that the serverless flag is turned off. However; after enough hours of inactivity the service will stop responding to all requests, I don't even see them show up in the HTTP log and I don't see any errors happening in any of the other logs. A simple server restart fixes the issue immediately. I am not sure if there is something configured incorrectly on my end or if it is an issue on railways end. Thanks in advance!
6 Replies
23 days ago
This thread has been marked as public for community involvement, as it does not contain any sensitive or personal information. Any further activity in this thread will be visible to everyone.
Status changed to Open Railway • 23 days ago
23 days ago
I would treat this as two separate checks: whether Railway is actually putting the service to sleep, and whether the Go process is still running but no longer reachable through the public domain.
The important detail is that you do not see the requests in your HTTP logs. If the log is written at the start of the handler and nothing appears, the request is probably not reaching your Go process. If the log is written after a database call or after the handler finishes, the app may still be receiving the request and blocking before your log line runs.
First, make sure the Go service is listening exactly the way Railway expects:
package main
import (
"log"
"net/http"
"os"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
})
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
server := &http.Server{
Addr: "0.0.0.0:" + port,
Handler: logRequests(mux),
ReadHeaderTimeout: 5 * time.Second,
}
log.Printf("listening on 0.0.0.0:%s", port)
log.Fatal(server.ListenAndServe())
}
func logRequests(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf(
"incoming request method=%s path=%s host=%s railway_request_id=%s",
r.Method,
r.URL.Path,
r.Host,
r.Header.Get("X-Railway-Request-Id"),
)
next.ServeHTTP(w, r)
})
}The two common mistakes are listening on localhost or 127.0.0.1, and hardcoding a port that is different from Railway's PORT variable. If your public domain has a target port set, make sure it matches the port your Go process is actually listening on.
Then add /healthz as the Railway healthcheck path. This will not continuously monitor the app after the deployment is live, but it does prove that Railway can reach the process before routing traffic to a new deployment. Keep this endpoint independent of MongoDB, Redis, third-party APIs, or any slow startup work. It should only prove that the Go server is alive.
For this specific symptom, I would test in this order:
- Confirm Serverless is disabled on the exact service and environment that owns the public domain.
- Confirm there is only one active deployment for that service and that the public domain points to this service, not an older service or duplicate environment.
- Confirm the app logs
listening on 0.0.0.0:$PORTon boot. - Confirm the public domain target port, if set, matches the app port.
- Add the request logger above and put the log line before any handler work.
- Add a lightweight
/healthzendpoint and hit it after the service has been idle for a few hours.
If /healthz works after idle but your normal route hangs, the service is not asleep. The app is blocking inside the normal request path. In a Go API that usually means a stale database connection, an outbound HTTP call without a timeout, a locked goroutine, or startup state that only fails after sitting idle.
For any database or external HTTP work, make sure every request has a timeout:
client := &http.Client{
Timeout: 10 * time.Second,
}For database calls, use request-scoped contexts:
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
err := db.PingContext(ctx)If /healthz also fails after idle and no request log appears, focus on Railway configuration: Serverless setting on the correct service, public networking target port, usage or replica limits, and whether the domain is attached to the expected service.
23 days ago
The GO program is running the whole time, I have an hourly cron job and when I look in the logs it is printing the message "Running hourly cron job...." ever hour. So I think it is some type of network issue, because the 4 jobs that are suppose to run don't seem to be running either (there are logs for each operation, i.e. clearing old audit logs, apply recurrences, etc...) and they are not printing anything. Though after the restart I can see that the hourly job is actually doing something, so it seems to be a networking issue, it can't accept requests or reach the database.
23 days ago
If the hourly cron log keeps printing, the service is probably not sleeping. The Go process is alive, but something in the network or database path is getting stuck after idle.
I would first add a log line before each of the 4 jobs starts, not only inside the job:
log.Printf("cron: starting clear old audit logs")
log.Printf("cron: starting apply recurrences")
If those "starting" logs appear but the matching success/error logs do not, the job is blocking inside the database or an outbound network call.
The most likely fix is to make every database/network operation use a timeout and avoid keeping stale idle DB connections forever:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := db.PingContext(ctx)
If you use database/sql, also set connection lifetimes:
db.SetMaxIdleConns(2)
db.SetConnMaxIdleTime(5 * time.Minute)
db.SetConnMaxLifetime(30 * time.Minute)
I would also keep a /healthz route that does not touch the database. When it happens again, test /healthz.
If /healthz works but normal routes and jobs hang, Railway is routing correctly and the app is blocked on DB/network I/O.
If /healthz also fails and there is no first-line request log, then check the listener/public networking side: the app should listen on 0.0.0.0:$PORT and the Railway domain target port should match that port.
23 days ago
If Serverless is really off, I would not assume the service is sleeping yet.
The important detail is that you don't see the request in the HTTP logs. That can mean either Railway is not routing to this service, or your Go app is receiving the request but your log happens too late in the handler.
First, add a dead simple /healthz route and log before doing any DB/API work.
Also make sure your Go server listens like this:
0.0.0.0: + os.Getenv("PORT")
not localhost, 127.0.0.1, or a hardcoded port.
Then test after the app has been idle:
- if
/healthzworks, the service is not asleep; your normal route is probably blocked on a stale DB connection or outbound request without timeout - if
/healthzalso never reaches your logs, check that the public domain is attached to the correct service/environment and that the target port matches your Go app
Btw, for Go APIs this kind of “works after restart, dies after idle” is often a stale external connection or missing timeout, not Railway sleep.
22 days ago
Hi mybro,
If requests do not show up in the HTTP logs, the issue may be happening before the request reaches the app, or the Go server may still be running but no longer accepting connections.
A restart fixing it immediately suggests the process/container gets into a stuck state after being idle, i would check a few things:
-
Make sure the Go server listens on Railway’s
$PORTand binds to0.0.0.0, notlocalhost. -
Add a simple
/healthendpoint and configure Railway healthchecks for it. -
Add request timeouts on the Go HTTP server, for example
ReadTimeout,WriteTimeout, andIdleTimeout. -
Check whether the app is waiting forever on a database or external API call after idle time. Any outbound call should have a timeout.
-
When it happens again, try Railway shell/SSH and test locally inside the container:
curl -v http://localhost:$PORT/health-
If local curl works but the public URL does not, it is likely a Railway routing/networking issue.
-
If local curl also hangs, the Go process is stuck and the app needs better healthchecks/timeouts so Railway can restart it automatically.
Also confirm that the service is not still using any sleep/serverless behavior.
19 days ago
I'm checking back in after a few days to confirm some things. Yes I can see that the cron jobs, and thus the go process itself is still running, however any operation that involves any network communication is hanging/not responding. i.e. I can see the cron jobs begin, but I am not getting any error or success messages, which to me implies they are hanging. And none of the HTTP endpoints respond, when I go to use the app or hit a health endpoint it just hangs, and returns a timeout response. I am 99% sure this is a railway networking issue and I am not sure if there is something I can do to configure it differently to resolve this issue or not. One thing to note, is that if there is continuing requests, that don't have more than 6-12 hour in between them (I haven't tested how long exactly, so this is a rough time estimate range), then it seems as though it does not do this sleep thing. It did not seem to go to sleep tonight, i.e. still operational this morning, but I could see that there were enough requests during the night which kept it operational. I would greatly appreciate if one of the Railway staff members could possible help me diagnosis this problem, thank you.
Status changed to Open dev • 7 days ago