Tyk Session Stickiness and Custom Plugins Integration

Hello, Tyk community,

I’m exploring the possibility of using Tyk with session stickiness in our organization.
While researching, I came across an old forum message that confirms the lack of session stickiness support in Tyk.
Can anyone confirm if Tyk now supports session stickiness, or if there are alternative methods to achieve this? Specifically, I’m interested in understanding if custom plugins can be utilized within a request scope to handle session stickiness, rather than relying on the API definition scope.

To provide some context, we already have a dedicated service responsible for managing session stickiness, and we currently call it inside a middleware. Unfortunately, we have faced challenges when attempting to integrate it with Tyk seamlessly.

For example, if a user sends a request to https://tyk-gateway/greeters, without any type of stickiness the request will be forwarded to http://greeter-lb:8080/greeters, but we need the plugin GetStickyServiceAddress to override greeter-lb:8080 with a custom address, i.e. 240.2.2.4:8080.
This is because we have an internal logic that takes into account multiple factors.

The API definition:

{
  "name": "greeter",
  "slug": "greeter",
  "api_id": "greeter",
  "org_id": "greeters.com",
  "use_keyless": true,
  "enable_context_vars": true,
  "auth": {
    "auth_header_name": ""
  },
  "definition": {
    "location": "",
    "key": "",
    "strip_path": false
  },
  "version_data": {
    "not_versioned": true,
    "versions": {
      "Default": {
        "name": "Default",
        "expires": "",
        "paths": {
          "ignored": null,
          "white_list": null,
          "black_list": null
        },
        "use_extended_paths": false,
        "extended_paths": {},
        "global_headers": {},
        "global_headers_remove": null,
        "global_response_headers": null,
        "global_response_headers_remove": null,
        "ignore_endpoint_case": false,
        "global_size_limit": 0,
        "override_target": ""
      }
    }
  },
  "custom_middleware": {
    "pre": [
      {
        "name": "GetStickyServiceAddress",
        "path": "/mnt/tyk-gateway/plugins/stickiness-service.so"
      }
    ],
    "post_key_auth": [],
    "auth_check": {},
    "post": [],
    "driver": "goplugin"
  },
  "proxy": {
    "listen_path": "/greeters",
    "target_url": "http://greeter-lb:8080",
    "strip_listen_path": false
  },
  "active": true
}

We tried to implement the solution using this example, but the provided solution affects the API definition scope and not a request scope.

If anyone has experience or insights into this matter, I would greatly appreciate your guidance. Additionally, if there are best practices or examples of successful integrations with similar setups, that information would be invaluable.

Thank you in advance for your assistance.

Haviv.

1 Like

To answer my question. This can be done by combining a custom pre-request plugin, header or session metadata injection, and URL rewriting.

API Definition:

        "use_extended_paths": true,
        "extended_paths": {
          "url_rewrites": [
            {
              "path": "/v1/{.*}",
              "match_pattern": "/(.*)",
              "method": "GET",
              "rewrite_to": "http://greeter-lb:8080/$1", // fallback
              "triggers": [
                {
                  "on": "all",
                  "options": {
                    "header_matches": {
                      "Service-Address": {
                        "match_rx": ".*"
                      }
                    }
                  },
                  "rewrite_to": "$tyk_context.trigger-0-Service-Address-0/$1" // override
                }
              ]
            }
          ]
        },

In the Go middleware you can simply call

func GetGreeterAddress(w http.ResponseWriter, r *http.Request) {
  // logic
  // ... 
  r.Header.Set("Service-Address", serviceAddress)
}
1 Like