New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@gremlin/failure-flags

Package Overview
Dependencies
Maintainers
2
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@gremlin/failure-flags - npm Package Compare versions

Comparing version 0.0.18 to 1.0.0

6

index.js

@@ -20,4 +20,4 @@ /*

const ifExperimentActive = async ({name, labels, behavior = defaultBehavior, dataPrototype = null, debug = false}) => {
if(debug) console.log('ifExperimentActive', name, labels, dataPrototype);
const invokeFailureFlag = async ({name, labels, behavior = defaultBehavior, dataPrototype = null, debug = false}) => {
if(debug) console.log('invokeFailureFlag', name, labels, dataPrototype);
if (typeof behavior != 'function') {

@@ -77,2 +77,2 @@ if(debug) console.log('behavior is not a function');

module.exports = exports = { ifExperimentActive, fetchExperiment, effect, defaultBehavior };
module.exports = exports = { invokeFailureFlag, fetchExperiment, effect, defaultBehavior };

@@ -236,4 +236,4 @@ /*

test('ifExperimentActive does nothing if callback is not a function', async () => {
expect(await failureflags.ifExperimentActive({
test('invokeFailureFlag does nothing if callback is not a function', async () => {
expect(await failureflags.invokeFailureFlag({
name: 'custom',

@@ -246,4 +246,4 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive does nothing if no experiment for failure flag', async () => {
expect(await failureflags.ifExperimentActive({
test('invokeFailureFlag does nothing if no experiment for failure flag', async () => {
expect(await failureflags.invokeFailureFlag({
name: 'doesnotexist',

@@ -256,4 +256,4 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive does call callback', async () => {
expect(await failureflags.ifExperimentActive({
test('invokeFailureFlag does call callback', async () => {
expect(await failureflags.invokeFailureFlag({
name: 'custom',

@@ -265,5 +265,5 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive does nothing if FAILURE_FLAGS_ENABLED is not truthy', async () => {
test('invokeFailureFlag does nothing if FAILURE_FLAGS_ENABLED is not truthy', async () => {
delete process.env.FAILURE_FLAGS_ENABLED
expect(await failureflags.ifExperimentActive({
expect(await failureflags.invokeFailureFlag({
name: 'custom',

@@ -274,5 +274,5 @@ labels: {a:'1',b:'2'}})).toBe(false);

test('ifExperimentActive does nothing if all experiments probablistically skipped', async () => {
test('invokeFailureFlag does nothing if all experiments probablistically skipped', async () => {
try {
expect(await failureflags.ifExperimentActive({
expect(await failureflags.invokeFailureFlag({
name: 'defaultBehaviorZeroRate',

@@ -288,6 +288,6 @@ labels: {a:'1',b:'2'},

test('around / instead example', async () => {
if (!await failureflags.ifExperimentActive({name:'custom'})) {
if (!await failureflags.invokeFailureFlag({name:'custom'})) {
expect(true).toBe(false); // always reject if this line is reached.
}
if (await failureflags.ifExperimentActive({name:'defaultBehaviorWithNoException'}) === true) {
if (await failureflags.invokeFailureFlag({name:'defaultBehaviorWithNoException'}) === true) {
expect(setTimeout).toHaveBeenCalledTimes(1);

@@ -297,5 +297,5 @@ }

test('ifExperimentActive default behavior is delayedException with default error message', async () => {
test('invokeFailureFlag default behavior is delayedException with default error message', async () => {
try {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'defaultBehavior',

@@ -313,5 +313,5 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive default behavior is delayedException with custom error message', async () => {
test('invokeFailureFlag default behavior is delayedException with custom error message', async () => {
try {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'defaultBehaviorWithMessage',

@@ -328,5 +328,5 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive default behavior is delayedException with no exception', async () => {
test('invokeFailureFlag default behavior is delayedException with no exception', async () => {
try {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'defaultBehaviorWithNoException',

@@ -342,3 +342,3 @@ labels: {a:'1',b:'2'},

test('latency supports number', async () => {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'latencySupportsNumber',

@@ -354,3 +354,3 @@ labels: {a:'1',b:'2'},

test('latency supports string', async () => {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'latencySupportsString',

@@ -366,3 +366,3 @@ labels: {a:'1',b:'2'},

test('latency supports object', async () => {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'latencySupportsObject',

@@ -379,3 +379,3 @@ labels: {a:'1',b:'2'},

try {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'exceptionSupportsString',

@@ -395,3 +395,3 @@ labels: {a:'1',b:'2'},

try {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'exceptionSupportsExtraProperties',

@@ -412,3 +412,3 @@ labels: {a:'1',b:'2'},

try {
await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'exceptionSupportsExtraPropertiesAndMessage',

@@ -427,5 +427,5 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive true if dataPrototype unset and experiment active', async () => {
test('invokeFailureFlag true if dataPrototype unset and experiment active', async () => {
try {
const response = await failureflags.ifExperimentActive({
const response = await failureflags.invokeFailureFlag({
name: 'defaultBehaviorWithNoException',

@@ -443,6 +443,6 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive returns derrived if dataPrototype set and experiment active', async () => {
test('invokeFailureFlag returns derrived if dataPrototype set and experiment active', async () => {
let data = { property1: 'prototype value', property2: 'prototype value' };
try {
data = await failureflags.ifExperimentActive({
data = await failureflags.invokeFailureFlag({
name: 'alteredResponseValue',

@@ -463,6 +463,6 @@ labels: {a:'1',b:'2'},

test('ifExperimentActive returns dataPrototype if dataPrototype is set and no experiment active', async () => {
test('invokeFailureFlag returns dataPrototype if dataPrototype is set and no experiment active', async () => {
let response = {property1: "prototype value"};
try {
response = await failureflags.ifExperimentActive({
response = await failureflags.invokeFailureFlag({
name: 'doesnotexist',

@@ -469,0 +469,0 @@ labels: {a:'1',b:'2'},

{
"name": "@gremlin/failure-flags",
"version": "0.0.18",
"version": "1.0.0",
"description": "Failure Flags is a node SDK for working with the Gremlin fault injection platform to build application-level chaos experiments and reliability tests. This library works in concert with Gremlin-Lambda, a Lambda extension, or Gremlin-Container a container sidecar agent. This architecture minimizes the impact to your application code, simplifies configuration, and makes adoption painless.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -28,3 +28,3 @@ # failure-flags

await failureflags.ifExperimentActive({
await failureflags.invokeFailureFlag({
name: 'flagname', // the name of your failure flag

@@ -48,3 +48,3 @@ labels: {}) // additional attibutes about this invocation

// effects it describes.
await gremlin.ifExperimentActive({
await gremlin.invokeFailureFlag({
name: 'http-ingress',

@@ -66,4 +66,8 @@ labels: {

## Enabling the SDK in your Environment
*Don't forget to enable the SDK by setting the FAILURE_FLAGS_ENABLED environment variable!* If this environment variable is not set then the SDK will short-circuit and no attempt to fetch experiments will be made.
## Extensibility
You can always bring your own behaviors and effects by providing a behavior function. Here's another Lambda example that writes the experiment data to the console instead of changing the application behavior:

@@ -81,3 +85,3 @@

// effects it describes.
await gremlin.ifExperimentActive({
await gremlin.invokeFailureFlag({
name: 'http-ingress',

@@ -103,9 +107,26 @@ labels: {

### Doing Something Different
### Providing Metadata to Custom Effects
Sometimes you need even more manual control. For example, in the event of an experiment you might not want to make some API call or need to rollback some transaction. In most cases the Exception effect can help, but the `ifExperimentActive` function also returns a boolean to indicate if there was an experiment. You can use that to create branches in your code like you would for any feature flag.
The default effect chain included with the Failure Flags SDK is aware of well-known effect properties including, "latency" and "exception." The user can extend or replace that functionality and use the same properties, or provide their own. For example, suppose a user wants to use a "random jitter" effect that the Standard Chain does not provide. Suppose they wanted to inject a random amount of jitter up to some maximum. They could implement that small extension and make up their own Effect property called, "my-jitter" that specifies that maximum. The resulting Effect Statement would look like:
```json
{ "my-jitter": 500 }
```
They might also combine this with parts of the default chain:
```json
{
"latency": 1000,
"my-jitter": 500
}
```
## Alternatively, use it like a Feature Flag
Sometimes you need even more manual control. For example, in the event of an experiment you might not want to make some API call or need to rollback some transaction. In most cases the Exception effect can help, but the `invokeFailureFlag` function also returns a boolean to indicate if there was an experiment. You can use that to create branches in your code like you would for any feature flag.
```js
...
if (await failureflags.ifExperimentActive({name:'myFlag'})) {
if (await failureflags.invokeFailureFlag({name:'myFlag'})) {
// if there is a running experiment then do this

@@ -122,3 +143,3 @@ } else {

## Targeting with Selectors
## Building Experiments: Targeting with Selectors

@@ -187,3 +208,3 @@ Experiments match specific invocations of a Failure Flag based on its name, and the labels you provide. Experiments define Selectors that the Failure Flags engine uses to determine if an invocation matches. Selectors are simple key to list of values maps. The basic matching logic is every key in a selector must be present in the Failure Flag labels, and at least one of the values in the list for a selector key must match the value in the label.

Suppose you want to be able to experiment with mangled data. This might include responses from your application's dependencies. You can do that with a little extra work. You need to provide prototype data in your call to `ifExperimentActive`.
Suppose you want to be able to experiment with mangled data. This might include responses from your application's dependencies. You can do that with a little extra work. You need to provide prototype data in your call to `invokeFailureFlag`.

@@ -194,3 +215,3 @@ ```js

myData = await failureflags.ifExperimentActive({
myData = await failureflags.invokeFailureFlag({
name: 'flagname', // the name of your failure flag

@@ -225,18 +246,1 @@ labels: {}, // additional attibutes about this invocation

This is exciting because it means that you do not need to mock out whole responses before you know what experiments you'll need to run.
### Advanced: Providing Metadata to Custom Effects
The default effect chain included with the Failure Flags SDK is aware of well-known effect properties including, "latency" and "exception." The user can extend or replace that functionality and use the same properties, or provide their own. For example, suppose a user wants to use a "random jitter" effect that the Standard Chain does not provide. Suppose they wanted to inject a random amount of jitter up to some maximum. They could implement that small extension and make up their own Effect property called, "my-jitter" that specifies that maximum. The resulting Effect Statement would look like:
```json
{ "my-jitter": 500 }
```
They might also combine this with parts of the default chain:
```json
{
"latency": 1000,
"my-jitter": 500
}
```

@@ -20,3 +20,3 @@ /*

const fetchExperiment = async (name, labels = {}, debug = false) => {
labels["failure-flags-sdk-version"] = pjson.version;
labels["failure-flags-sdk-version"] = "node-v" + pjson.version;

@@ -23,0 +23,0 @@ if(debug) console.log('fetch experiment for', name, labels);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc