-
Notifications
You must be signed in to change notification settings - Fork 347
Description
I keep getting the following timeout errors:
Post https://api.push.apple.com/3/device/[xxx]: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
This is quickly followed by the following crash:
panic: runtime error: invalid memory address or nil pointer dereference
They're happening every 10-15 minutes, but only started happening in the last week or so. I tried throttling down the number of requests that were going through the server from around 1k per minute to just 50 or so per minute, but I'm still getting the crash.
I am running go1.12.17 and am using the latest version of apns2 from the master branch.
I'm a relative newbie when it comes to golang, so I'm going to post my code below. Perhaps I'm doing something wrong - but this push notification server has been working without issue for over a year and only recently started having a problem.
Any help you can provide (especially @sideshow ) would be greatly appreciated!
type PushBatch struct {
PushNotifications []PushNotification `json:"pushNotification"`
}
type PushNotification struct {
ObjectID string `json:"objectId"`
DeviceToken string `json:"deviceToken"`
Topic string `json:"topic"`
CollapseID string `json:"collapseId"`
Payload string `json:"payload"`
Type string `json:"pushType"`
}
var prodClient *apns2.Client
func collectPush(rw http.ResponseWriter, req *http.Request) {
decoder := json.NewDecoder(req.Body)
var p PushBatch
err := decoder.Decode(&p)
if err != nil {
panic(err)
}
count := len(p.PushNotifications)
notifications := make(chan *apns2.Notification, 50)
responses := make(chan *apns2.Response, count)
for i := 0; i < 20; i++ {
go worker(notifications, responses)
}
for _, p := range p.PushNotifications {
notifications <- n
}
for _, p := range p.PushNotifications {
res := <-responses
}
close(notifications)
close(responses)
rw.WriteHeader(200)
}
func worker(notifications <-chan *apns2.Notification, responses chan<- *apns2.Response) {
for n := range notifications {
// initiate push
res, err := prodClient.Push(n)
if err != nil {
fmt.Printf("Push Error: %v", err)
}
responses <- res
}
}
func main() {
// auth key
authKey, err := token.AuthKeyFromFile("XXXX")
if err != nil {
log.Fatal("token error:", err)
}
// token
token := &token.Token{
AuthKey: authKey,
// KeyID from developer account (Certificates, Identifiers & Profiles -> Keys)
KeyID: "XXXX",
// TeamID from developer account (View Account -> Membership)
TeamID: "XXXXX",
}
// client setup
devClient = apns2.NewTokenClient(token)
prodClient = apns2.NewTokenClient(token)
prodClient.Production()
// apns2.HTTPClientTimeout = 200 * time.Second
// apns2.TCPKeepAlive = 200 * time.Second
// get port
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
// start server
http.HandleFunc("/", collectPush)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
One thing I'm wondering - when I call into my server with a new batch of push notifications, does my current code spawn a bunch of new workers on top of any existing workers, thus creating a potentially huge group of workers? What I want to do is just add any new batches of push notifications to an existing queue - if this isn't doing that, would appreciate some sample code showing how to do this.