Virtual path, parallelism problem


#1

Imported Google Group message. Original thread at: https://groups.google.com/forum/#!topic/tyk-community-support/c3BXZGCgsvw Import Date: 2016-01-19 21:31:24 +0000.
Sender:Saheed Chavarría.
Date:Tuesday, 17 November 2015 02:36:49 UTC.

I created a virtual path (the sample included with Tyk) and tested the endpoint from JMeter with several threads ( 2 or more) sending at the same time and I got problems where it keeps telling me variables in JS are undefined, for example the session or request object (this is when I write a simple function that just returns a fixed value).

As I said, it is the included example “thisTest” that I used, and also wrote my own (a very simple one).

I’ll be very happy if you have any help for me.

thanks in advance.

INFO[1543] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1543] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1543] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1543] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1543] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
ERRO[1544] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1544] --> Returned: undefined
ERRO[1544] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1544] --> Returned: undefined
ERRO[1544] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1544] --> Returned: undefined
INFO[1574] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1574] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
ERRO[1574] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1574] --> Returned: undefined
INFO[1574] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1574] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
INFO[1574] [JSVM] [LOG]: [Virtual Test] Making Upstream Batch Request
ERRO[1574] Could not decode batch request, decoding failed: invalid character ‘u’ looking for beginning of value
ERRO[1574] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1574] --> Returned: undefined
ERRO[1574] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1574] --> Returned: undefined
ERRO[1574] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[1574] --> Returned: undefined


#2

Imported Google Group message.
Sender:Martin Buhr.
Date:Wednesday, 18 November 2015 08:11:39 UTC.

Hi Saheed,

Have dug a little deeper and there could be a concurrency issue in the JSVM, I’ve released a hotfix that addresses it - it’s a drop-in replacement of the binary, nothing else needs to change - can you let me know how you get on with this version?

Many thanks,
Martin


#3

Imported Google Group message.
Sender:Saheed Chavarría.
Date:Tuesday, 17 November 2015 08:36:42 UTC.

hi Saheed,

It might just be because there is no meta_data associated with the token used to make the request, in the return statement, change it to just return an empty object:

From:

function batchTest(request, session, config) {
// Set up a response object
var response = {
Body: “”
Headers: {
“test”: “virtual-header-1”,
“test-2”: “virtual-header-2”,
“content-type”: “application/json”
},
Code: 200
}

// Batch request
var batch = {
    "requests": [
        {
            "method": "GET",
            "headers": {
                "x-tyk-test": "1",
                "x-tyk-version": "1.2",
                "authorization": "1dbc83b9c431649d7698faa9797e2900f"
            },
            "body": "",
            "relative_url": "http://httpbin.org/get"
        },
        {
            "method": "GET",
            "headers": {},
            "body": "",
            "relative_url": "http://httpbin.org/user-agent"
        }
    ],
    "suppress_parallel_execution": false
}


log("[Virtual Test] Making Upstream Batch Request")
var newBody = TykBatchRequest(JSON.stringify(batch))


// We know that the requests return JSON in their body, lets flatten it
var asJS = JSON.parse(newBody)
for (var i in asJS) {
    asJS[i].body = JSON.parse(asJS[i].body)
}


// We need to send a string object back to Tyk to embed in the response
response.Body = JSON.stringify(asJS)


return TykJsResponse(response, session.meta_data)

}

To:

function batchTest(request, session, config) {
// Set up a response object
var response = {
Body: “”
Headers: {
“test”: “virtual-header-1”,
“test-2”: “virtual-header-2”,
“content-type”: “application/json”
},
Code: 200
}

// Batch request
var batch = {
    "requests": [
        {
            "method": "GET",
            "headers": {
                "x-tyk-test": "1",
                "x-tyk-version": "1.2",
                "authorization": "1dbc83b9c431649d7698faa9797e2900f"
            },
            "body": "",
            "relative_url": "http://httpbin.org/get"
        },
        {
            "method": "GET",
            "headers": {},
            "body": "",
            "relative_url": "http://httpbin.org/user-agent"
        }
    ],
    "suppress_parallel_execution": false
}


log("[Virtual Test] Making Upstream Batch Request")
var newBody = TykBatchRequest(JSON.stringify(batch))


// We know that the requests return JSON in their body, lets flatten it
var asJS = JSON.parse(newBody)
for (var i in asJS) {
    asJS[i].body = JSON.parse(asJS[i].body)
}


// We need to send a string object back to Tyk to embed in the response
response.Body = JSON.stringify(asJS)


return TykJsResponse(response, {})

}

Cheers,
Martin


#4

Imported Google Group message.
Sender:Martin Buhr.
Date:Tuesday, 17 November 2015 21:45:19 UTC.

Hi Mark.

Just changing the session reference to {} didn’t work, but I just made something that seems to work, but I’ve got to know why.

  1. I used a simpler function that only creates a response object and returns it (it doesn’t make any request to other endpoints), I also removed any “log” writing.
  2. I defined all the variables used in the function, outside the function, and just fill and use them inside the function.
  3. Instead of using TykJsResponse to return the result, I saw that it just makes a stringify, so I did it directly.

Without 2 or 3, it doesn’t work.

As I said I used JMeter to send several requests at a time, let’s say 10 just to test, and got errors like
ERRO[0012] --> Returned: undefined
ERRO[0012] Failed to decode virtual endpoint response data on return from VM: invalid character ‘u’ looking for beginning of value
ERRO[0012] http: proxy error: dial tcp [::1]:80: getsockopt: connection refused

The API definition in TYK is a simple API with no authentication, no cache, no nothing, just the Virtual Path and the function defined in the code editor.

Cheers.

  • show quoted text -

#5

Imported Google Group message.
Sender:Saheed Chavarría.
Date:Tuesday, 17 November 2015 21:56:07 UTC.

Are you using the docker version or a manual install?

Are you getting the undefined error on every request (maybe just make it manually) or only intermittently?

You’re getting a connection refused error - what are you calling in the JS script and is it running?

Cheers,
Martin

  • show quoted text -

#6

Imported Google Group message.
Sender:Martin Buhr.
Date:Tuesday, 17 November 2015 22:18:53 UTC.

  1. Manual install
  2. Intermittently. If I send requests to endpoint in sync mode, I got no errors, but with several threads at a time, it gives the error intermittlenly
  3. The function I’m calling is
    var SVret;
    var SVreq;
    var SVcont;
    var SVresponseObject;

function RandomSV(SVrequest, SVsession, SVconfig) {

SVreq = SVrequest;

SVresponseObject = {
Body: “THIS IS A VIRTUAL RESPONSE n=” + Math.random()
Headers: {
“test”: “virtual”,
“test-2”: “virtual”
},
Code: 200
}

try {

  //SVret = TykJsResponse(SVresponseObject, {});
 SVret = JSON.stringify({Response: SVresponseObject, SessionMeta: {}});
  //console.log("ret", SVret);

} catch (SVerr) {
 console.log("ERROR vs:", SVerr);
 SVret = JSON.stringify({Response: {}, SessionMeta: {}});
}

return SVret;

}

  • show quoted text -

#7

Imported Google Group message.
Sender:Saheed Chavarría.
Date:Tuesday, 17 November 2015 22:30:06 UTC.

Ok cool - thanks for sending - that is a little bizarre so will need to investigate a bit deeper, that shouldn’t be happening.

Interestingly, if you are re-defining the return object each time the function is run, then you can get a conflict if is accessed async since one request might be redefining the SVResponseObject while the other is trying to return it (and the reference will be lost), it could be a uirk in the VM.

The vars should definitely be initialised within the function, not outside to keep them thread safe.

Will take a look… very odd behaviour.

M.

  • show quoted text -

#8

Imported Google Group message.
Sender:Martin Buhr.
Date:Wednesday, 18 November 2015 16:29:23 UTC.

Hi Martin.

I just installed and checked the fix and everything was perfect running the example.

Many thanks for your fast response !!!

I have more complex scenarios with Virtual paths that I would be testing today with this fix.

Cheers.

  • show quoted text -