changeset 3161:6a44a89ffb51

SOAP: Added a globally configurable timeout (default 1min) till a SOAP request is canceled.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 06 May 2019 13:19:59 +0200
parents 94935895e6d7
children 659549608644
files pkg/config/config.go pkg/imports/erdms.go pkg/soap/soap.go
diffstat 3 files changed, 42 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/config/config.go	Mon May 06 13:05:49 2019 +0200
+++ b/pkg/config/config.go	Mon May 06 13:19:59 2019 +0200
@@ -22,6 +22,7 @@
 	"time"
 
 	homedir "github.com/mitchellh/go-homedir"
+
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 
@@ -110,6 +111,11 @@
 // to be served to to the web client.
 func PublishedConfig() string { return viper.GetString("published-config") }
 
+// SOAPTimeout is the timeout till a SOAP request is canceled.
+func SOAPTimeout() time.Duration {
+	return viper.GetDuration("soap-timeout")
+}
+
 var (
 	proxyKeyOnce       sync.Once
 	proxyKey           []byte
@@ -229,6 +235,10 @@
 		fl.Bool(name, value, usage)
 		vbind(name)
 	}
+	d := func(name string, value time.Duration, usage string) {
+		fl.Duration(name, value, usage)
+		vbind(name)
+	}
 
 	strP("db-host", "H", "localhost", "host of the database")
 	uiP("db-port", "P", 5432, "port of the database")
@@ -273,6 +283,8 @@
 	str("schema-dirs", ".", "Directories to find XSD schema files in (recursive).")
 
 	str("published-config", "", "path to a config file served to client.")
+
+	d("soap-timeout", time.Minute, "Timeout till a SOAP request is canceled.")
 }
 
 var (
--- a/pkg/imports/erdms.go	Mon May 06 13:05:49 2019 +0200
+++ b/pkg/imports/erdms.go	Mon May 06 13:19:59 2019 +0200
@@ -18,6 +18,7 @@
 	"context"
 	"database/sql"
 	"fmt"
+	"log"
 	"strings"
 
 	"gemma.intevation.de/gemma/pkg/soap"
@@ -93,8 +94,18 @@
 			},
 		}
 
+		const maxTries = 3
+
+		tries := 0
+
+	again:
 		data, err := client.GetRisDataXML(request)
 		if err != nil {
+			if t, ok := err.(interface{ Timeout() bool }); ok && t.Timeout() && tries < maxTries {
+				log.Println("warn: ERDMS SOAP request timed out. Trying again.")
+				tries++
+				goto again
+			}
 			return nil, fmt.Errorf("Error requesting ERDMS service: %v", err)
 		}
 		responseData = append(responseData, data)
--- a/pkg/soap/soap.go	Mon May 06 13:05:49 2019 +0200
+++ b/pkg/soap/soap.go	Mon May 06 13:19:59 2019 +0200
@@ -15,6 +15,7 @@
 
 import (
 	"bytes"
+	"context"
 	"crypto/tls"
 	"encoding/xml"
 	"fmt"
@@ -23,7 +24,10 @@
 	"math/rand"
 	"net"
 	"net/http"
+	"sync"
 	"time"
+
+	"gemma.intevation.de/gemma/pkg/config"
 )
 
 const timeout = time.Duration(30 * time.Second)
@@ -272,6 +276,21 @@
 
 	client := &http.Client{Transport: tr}
 
+	timeout := config.SOAPTimeout()
+
+	ctx, cancel := context.WithTimeout(context.Background(), timeout)
+
+	var once sync.Once
+
+	defer once.Do(cancel)
+
+	req = req.WithContext(ctx)
+
+	go func() {
+		defer once.Do(cancel)
+		<-ctx.Done()
+	}()
+
 	res, err := client.Do(req)
 	if err != nil {
 		return err