From 280f6183be7e1c2c18644cf13042e48d0b26adcb Mon Sep 17 00:00:00 2001 From: Luan van Pletsen Date: Tue, 20 Feb 2018 12:12:43 +0000 Subject: [PATCH 1/4] Add Debug messages for JSVM Timeout --- mw_js_plugin.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mw_js_plugin.go b/mw_js_plugin.go index d5c3adafca9..c1dfa77a8e7 100644 --- a/mw_js_plugin.go +++ b/mw_js_plugin.go @@ -341,8 +341,14 @@ func (j *JSVM) Init(spec *APISpec) { if config.Global.JSVMTimeout <= 0 { j.Timeout = time.Duration(defaultJSVMTimeout) * time.Second + log.WithFields(logrus.Fields{ + "prefix": "jsvm", + }).Debugf("Default JSVM timeout used: %v", j.Timeout) } else { j.Timeout = time.Duration(config.Global.JSVMTimeout) * time.Second + log.WithFields(logrus.Fields{ + "prefix": "jsvm", + }).Debugf("Custom JSVM timeout: %v", j.Timeout) } j.Log = log // use the global logger by default From 3cb6d2bb4411b69b7202d3208d91c0f5ef834b56 Mon Sep 17 00:00:00 2001 From: Luan van Pletsen Date: Wed, 21 Feb 2018 09:43:51 +0000 Subject: [PATCH 2/4] Add JSVM Timeout check to VirtualEndpoint.ServeHTTPForCache --- mw_virtual_endpoint.go | 59 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/mw_virtual_endpoint.go b/mw_virtual_endpoint.go index 34c7eb76f77..d3470fe027f 100644 --- a/mw_virtual_endpoint.go +++ b/mw_virtual_endpoint.go @@ -11,9 +11,14 @@ import ( "strconv" "time" + "github.com/robertkrimen/otto" + _ "github.com/robertkrimen/otto/underscore" + "github.com/TykTechnologies/tyk/apidef" "github.com/TykTechnologies/tyk/config" "github.com/TykTechnologies/tyk/user" + + "github.com/Sirupsen/logrus" ) // RequestObject is marshalled to JSON string and passed into JSON middleware @@ -152,16 +157,62 @@ func (d *VirtualEndpoint) ServeHTTPForCache(w http.ResponseWriter, r *http.Reque log.Error("Failed to encode session for VM: ", err) return nil } + + // Run the middleware + // vm := d.Spec.JSVM.VM.Copy() + // returnRaw, err := vm.Run(vmeta.ResponseFunctionName + `(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`) + // if err != nil { + // log.Error("Failed to run virtual endpoint JS code:", err) + // return nil + // } + // returnDataStr, _ := returnRaw.ToString() // Run the middleware vm := d.Spec.JSVM.VM.Copy() - returnRaw, err := vm.Run(vmeta.ResponseFunctionName + `(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`) - if err != nil { - log.Error("Failed to run virtual endpoint JS code:", err) + vm.Interrupt = make(chan func(), 1) + log.WithFields(logrus.Fields{ + "prefix": "jsvm", + }).Debug("Running: ", vmeta.ResponseFunctionName) + // buffered, leaving no chance of a goroutine leak since the + // spawned goroutine will send 0 or 1 values. + ret := make(chan otto.Value, 1) + errRet := make(chan error, 1) + go func() { + defer func() { + // the VM executes the panic func that gets it + // to stop, so we must recover here to not crash + // the whole Go program. + recover() + }() + returnRaw, err := vm.Run(vmeta.ResponseFunctionName + `(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`) + ret <- returnRaw + errRet <- err + }() + var returnRaw otto.Value + t := time.NewTimer(d.Spec.JSVM.Timeout) + select { + case returnRaw = <-ret: + if err := <-errRet; err != nil { + log.WithFields(logrus.Fields{ + "prefix": "jsvm", + }).Error("Failed to run JS middleware: ", err) + return nil + } + t.Stop() + case <-t.C: + t.Stop() + log.WithFields(logrus.Fields{ + "prefix": "jsvm", + }).Error("JS middleware timed out after ", d.Spec.JSVM.Timeout) + vm.Interrupt <- func() { + // only way to stop the VM is to send it a func + // that panics. + panic("stop") + } return nil } returnDataStr, _ := returnRaw.ToString() - + // Decode the return object newResponseData := VMResponseObject{} if err := json.Unmarshal([]byte(returnDataStr), &newResponseData); err != nil { From fb6f059eb5e099d00263b6b47904ba3222da1479 Mon Sep 17 00:00:00 2001 From: Luan van Pletsen Date: Wed, 21 Feb 2018 10:00:43 +0000 Subject: [PATCH 3/4] Reformat --- mw_virtual_endpoint.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mw_virtual_endpoint.go b/mw_virtual_endpoint.go index d3470fe027f..e126d84cedf 100644 --- a/mw_virtual_endpoint.go +++ b/mw_virtual_endpoint.go @@ -157,7 +157,7 @@ func (d *VirtualEndpoint) ServeHTTPForCache(w http.ResponseWriter, r *http.Reque log.Error("Failed to encode session for VM: ", err) return nil } - + // Run the middleware // vm := d.Spec.JSVM.VM.Copy() // returnRaw, err := vm.Run(vmeta.ResponseFunctionName + `(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`) @@ -212,7 +212,7 @@ func (d *VirtualEndpoint) ServeHTTPForCache(w http.ResponseWriter, r *http.Reque return nil } returnDataStr, _ := returnRaw.ToString() - + // Decode the return object newResponseData := VMResponseObject{} if err := json.Unmarshal([]byte(returnDataStr), &newResponseData); err != nil { From dbf042be48d492d7047427a26e15ddcac4c9427b Mon Sep 17 00:00:00 2001 From: Luan van Pletsen Date: Wed, 21 Feb 2018 10:50:05 +0000 Subject: [PATCH 4/4] Reformat --- mw_virtual_endpoint.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/mw_virtual_endpoint.go b/mw_virtual_endpoint.go index e126d84cedf..d940f047a51 100644 --- a/mw_virtual_endpoint.go +++ b/mw_virtual_endpoint.go @@ -158,15 +158,6 @@ func (d *VirtualEndpoint) ServeHTTPForCache(w http.ResponseWriter, r *http.Reque return nil } - // Run the middleware - // vm := d.Spec.JSVM.VM.Copy() - // returnRaw, err := vm.Run(vmeta.ResponseFunctionName + `(` + string(requestAsJson) + `, ` + string(sessionAsJson) + `, ` + specAsJson + `);`) - // if err != nil { - // log.Error("Failed to run virtual endpoint JS code:", err) - // return nil - // } - // returnDataStr, _ := returnRaw.ToString() - // Run the middleware vm := d.Spec.JSVM.VM.Copy() vm.Interrupt = make(chan func(), 1)