README
Chainlink External Adapter Bootstrap
The core framework that every External Adapter uses.
Detailed here is optional configuration that can be provided to any EA through environment variables.
Table of Contents
Server configuration
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
BASE_URL |
Set a base url that is used for setting up routes on the external adapter. Ex. Typically a external adapter is served on the root, so you would make requests to / , setting BASE_URL to /coingecko would instead have requests made to /coingecko . Useful when multiple external adapters are being hosted under the same domain, and path mapping is being used to route between them. |
/ |
||
EA_PORT |
The port to run the external adapter's server on | 8080 |
||
UUID |
A universally unique identifier that is used to identify the EA | (generated randomly) | ||
DEBUG |
Toggles debug mode. | false |
||
NODE_ENV |
Toggles development mode. When set to developement the log messages will be prettified to be more read-able. | development |
undefined | |
LOG_LEVEL |
The winston log level. Set to debug for full log messages. | info , debug , trace |
info |
|
API_TIMEOUT |
The number of milliseconds a request can be pending before returning a timeout error. | 30000 |
||
API_ENDPOINT |
Override the base URL within the EA. | Defined in EA | ||
WS_API_ENDPOINT |
Override the base websocket URL within the EA. | Defined in EA | ||
API_VERBOSE |
Toggle whether the response from the EA should contain just the results or also include the full response body from the queried API. | false |
Performance
Caching
To cache data every adapter using the bootstrap
package has access to a simple LRU cache that will cache successful 200 responses using SHA1 hash of input as a key.
⚠️ Note
Please check and ensure caching is allowed and not in violation of the Terms of Service of the data provider's API. Disable caching flags if it is not supported by the specified API provider's TOS.
To configure caching these environment variables are available:
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
CACHE_ENABLED |
Toggle caching. | true |
||
CACHE_TYPE |
Which cache type should be used. | local or redis |
local |
|
CACHE_KEY_GROUP |
Set to specific group ID to group the cached data, for this adapter, with other instances in the same group. Applicable only in remote cache scenarios, where multiple adapter instances share the cache. | UUID of the adapter | ||
CACHE_KEY_IGNORED_PROPS |
Keys to ignore while deriving the cache key, delimited by , . The key set will be added to the default ignored keys |
['id', 'maxAge', 'meta', 'rateLimitMaxAge', 'debug', 'metricsMeta'] |
||
CACHE_MAX_AGE |
Maximum age in ms. Items are not pro-actively pruned out as they age, but if you try to get an item that is too old, it'll drop it and return undefined instead of giving it to you. If set to 0 the default will be used, and if set to < 0 entries will not persist in cache. |
90000 (1.5 minutes) |
||
CACHE_MIN_AGE |
Minimum age in ms. | 30000 (30 seconds) |
Cache key
The cache key of a stored request is derived by hashing the input object, using the SHA1 hash function, while by default ignoring keys ['id', 'maxAge', 'meta', 'rateLimitMaxAge', 'debug']
. So for example these few requests will derive the same key:
{"id": 1, "data": {"base":"LINK", "quote": "USD"}}
{"id": 2, "data": {"base":"LINK", "quote": "USD", "maxAge": 10000}}
{"id": 3, "data": {"base":"LINK", "quote": "USD"}}
The maxAge
input argument can be used to set per item maxAge
parameter. If not set, or set to 0
, the cache level maxAge
option will be used. Every time the maxAge
input argument changes, the item will be cached with the new maxAge
parameter. To avoid hitting the cache for a specific item set maxAge: -1
(any value < 0
).
Ignoring keys
If you want to ignore specific input data object keys, to be excluded from key derivation, you can use the CACHE_KEY_IGNORED_PROPS
environment variable.
For example, if the CACHE_KEY_IGNORED_PROPS=timestamp
is set, these requests will derive the same key:
{"id": 1, "data": {"base":"LINK", "quote": "USD", "timestamp": 1598874704}}
{"id": 2, "data": {"base":"LINK", "quote": "USD", "timestamp": 1598874721}}
Local cache
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
CACHE_MAX_ITEMS |
The maximum size of the cache, checked by applying the length function to all values in the cache. | 500 |
||
CACHE_UPDATE_AGE_ON_GET |
When using time-expiring entries with maxAge, setting this to true will make each item's effective time update to the current time whenever it is retrieved from cache, causing it to not expire. (It can still fall out of cache based on recency of use, of course.) | false |
Redis
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
CACHE_REDIS_HOST |
IP address of the Redis server. | 127.0.0.1 |
||
CACHE_REDIS_PORT |
Port of the Redis server. | 6379 |
||
CACHE_REDIS_PATH |
The UNIX socket string of the Redis server. | undefined | ||
CACHE_REDIS_URL |
The URL of the Redis server. Format: [redis[s]:]//[[user][:password@]][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]] . |
undefined | ||
CACHE_REDIS_PASSWORD |
The password required for redis auth. | null |
||
CACHE_REDIS_TIMEOUT |
The timeout in ms if connection to Redis errors or is not responding. | 500 |
For local development run a Redis Docker container:
docker run -p 6379:6379 --name ea-redis -d redis redis-server --requirepass SUPER_SECRET
For ElastiCache Redis deployments: if encryption in transit is used, to make a connection CACHE_REDIS_URL
needs to be set with rediss://...
protocol.
Rate Limiting
To avoid hitting rate limit issues with the data provider subscription, a rate limit capacity per minute can be set:
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
RATE_LIMIT_ENABLED |
Enabling Rate Limit functionality. | true |
Option 1, manual capacity setting:
Required? Name Description Options Defaults to RATE_LIMIT_CAPACITY
Maximum capacity on requests per minute undefined Option 2, capacity by reference. Check your plan here and use it with the following configuration:
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
RATE_LIMIT_API_PROVIDER |
Name of the provider. | The derived name of the running External Adapter | ||
RATE_LIMIT_API_TIER |
Plan you are subscribed to. | undefined |
Provider Limits
Each provider is defined within limits.json as so:
{
"[provider-name]": {
"http": {
"[plan-name]": {
"rateLimit1s": 1,
"rateLimit1m": 30,
"rateLimit1h": 200
},
"premium": {
"rateLimit1s": 10,
"rateLimit1m": 300,
"rateLimit1h": 2000
}
},
"ws": {
"[plan-name]": {
"connections": 1,
"subscriptions": 10
}
}
}, {...}
}
Being:
- provider-name: The provider name. E.g. "amberdata" or "coinmarketcap"
- plan-name: The provider plan name. Used as a identifier for the plan. E.g. "free" or "premium"
- There are two protocols with different limit types:
- http: With
rateLimit1s
,rateLimit1m
,rateLimit1h
, which stands for requests per second/minute/hour respectively. If only one is provided, the rest would be calculated based on it. - ws: Websocket limits, which accepts:
connections
andsubscriptions
. If websockets are not supported on the provider, can be left empty asws: {}
- http: With
Cache Warming
*To use this feature the CACHE_ENABLED
environment variable must also be enabled.
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
WARMUP_ENABLED |
Enable the cache warmer functionality. | true |
||
WARMUP_UNHEALTHY_THRESHOLD |
The number of times a warmup execution can fail before we drop a warmup subscription for a particular cache key.to. Set to -1 to disable. |
3 |
||
WARMUP_SUBSCRIPTION_TTL |
The maximum duration between requests for a cache key to an external adapter before the cache warmer will unsubscribe from warming up a particular cache key. | 3600000 (1 hour) |
||
WARMUP_INTERVAL |
The interval at which the cache warmer should send requests to warm the cache. | The cache's minimum TTL (30s) |
Request Coalescing
One final consideration is the “thundering herd” situation, in which many clients make requests that need the same uncached downstream resource at approximately the same time. This can also occur when a server comes up and joins the fleet with an empty local cache. This results in a large number of requests from each server going to the downstream dependency, which can lead to throttling/brownout. To remedy this issue we use request coalescing, where the servers or external cache ensure that only one pending request is out for uncached resources. Some caching libraries provide support for request coalescing, and some external inline caches (such as Nginx or Varnish) do as well. In addition, request coalescing can be implemented on top of existing caches. -- Amazon on Caching challenges and strategies
To configure caching these environment variables are available:
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
REQUEST_COALESCING_ENABLED |
Enable request coalescing. | false |
||
REQUEST_COALESCING_INTERVAL |
Interval in milliseconds for exponential back-off function. | 100 |
||
REQUEST_COALESCING_INTERVAL_MAX |
Maximum back-off in milliseconds. | 1000 |
||
REQUEST_COALESCING_INTERVAL_COEFFICIENT |
A coefficient as the base multiplier for exponential back-off interval function. | 2 |
||
REQUEST_COALESCING_ENTROPY_MAX |
Amount of random delay (entropy) in milliseconds that will be added to requests. Avoids issue where the request coalescing key won't be set before multiple other instances in a burst try to access the same key. | 0 |
||
REQUEST_COALESCING_MAX_RETRIES |
Maximum number of attempts to wait for the request coalescing key to be deleted before continuing this request | 5 |
Metrics
A metrics server can be exposed which returns prometheus compatible data on the metrics endpoint on the specified port.
When enabled, a metrics endpoint is opened on /metrics
, which can be prepended with the BASE_URL
if METRICS_USE_BASE_URL
is enabled.
*Please note that this feature is EXPERIMENTAL.
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
EXPERIMENTAL_METRICS_ENABLED |
Set to true to enable metrics collection. |
false |
||
METRICS_USE_BASE_URL |
Set to "true" to have the internal metrics endpoint use the supplied base url. | false |
||
METRICS_PORT |
The port the metrics endpoint is served on | 9080 |
||
METRICS_NAME |
set to apply a label of to each metric. | undefined |
To run Prometheus and Grafana with development setup:
yarn dev:metrics
Websockets
Adapters who interact with data providers that support websockets will be able to use them offering a WS interface. Each adapter will have its corresponding WS documentation.
Multiple subscription channels are multiplexed over one connection.
For every type of request, the adapter will subscribe to the corresponding channel.
From the moment the subscription is confirmed, the adapter will start receiving messages with the relevant information, piping this information to the cache. On future requests, the adapter will always have fresh data saved on cache. If there is no data available in cache, the adapter will continue with its default execution.
Required? | Name | Description | Options | Defaults to |
---|---|---|---|---|
WS_ENABLED |
Set this to true to enable WS support (on adapters that support this). |
false |
||
WS_SUBSCRIPTION_TTL |
Subscription expiration time in ms. If no new incoming requests ask for this information during this time, the subscription will be cancelled. | 120000 |
||
WS_SUBSCRIPTION_UNRESPONSIVE_TTL |
Unresponsive subscription expiration time in ms. If the adapter doesn't receive messages from an open subscription during this time, a resubscription will be tried. | 120000 |
*For the websockets to be effective, caching needs to be enabled