Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved SnapshotAutoUpdater schedule def #51

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ A clear and concise description of what you expected to happen.
- Deno version: e.g. (use deno --version)

```
deno 1.22.2 (release, x86_64-pc-windows-msvc)
v8 10.3.174.6
typescript 4.6.2
deno 1.41.0 (release, x86_64-pc-windows-msvc)
v8 12.1.285.27
typescript 5.3.3
```

**Additional context**
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ The context properties stores all information regarding connectivity.

> Initialization
```ts
import { Switcher } from "https://deno.land/x/switcher4deno@v1.0.2/mod.ts";
import { Switcher } from "https://deno.land/x/switcher4deno@v[VERSION]/mod.ts";

const url = 'https://switcherapi.com/api';
const url = 'https://api.switcherapi.com';
const apiKey = '[API_KEY]';
const environment = 'default';
const domain = 'My Domain';
Expand Down
7 changes: 6 additions & 1 deletion deno.jsonc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@switcherapi/switcher-client-deno",
"version": "1.0.7",
"description": "A Deno SDK for Switcher API",
"description": "Switcher4Deno is a Feature Flag Deno SDK client for Switcher API",
"tasks": {
"cache-reload": "deno cache --reload --lock=deno.lock --lock-write mod.ts",
"fmt": "deno fmt mod.ts src/ --options-single-quote --options-line-width=120 --check",
Expand All @@ -10,5 +10,10 @@
"lcov": "deno coverage coverage --lcov --output=coverage/report.lcov",
"clean": "rm -rf ./npm ./coverage ./generated-snapshots",
"cover": "deno task clean && deno task test && deno task lcov && genhtml -o coverage/html coverage/report.lcov"
},
"test": {
"include": [
"test/**/*.ts"
]
}
}
7 changes: 7 additions & 0 deletions snapshot/local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"data": {
"domain": {
"version": 0
}
}
}
10 changes: 10 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@ export const DEFAULT_LOGGER = false;
export const DEFAULT_TEST_MODE = false;
export const DEFAULT_REGEX_MAX_BLACKLISTED = 50;
export const DEFAULT_REGEX_MAX_TIME_LIMIT = 3000;

export enum SWITCHER_OPTIONS {
SNAPSHOT_LOCATION = 'snapshotLocation',
SNAPSHOT_AUTO_UPDATE_INTERVAL = 'snapshotAutoUpdateInterval',
SILENT_MODE = 'silentMode',
REGEX_SAFE = 'regexSafe',
REGEX_MAX_BLACK_LIST = 'regexMaxBlackList',
REGEX_MAX_TIME_LIMIT = 'regexMaxTimeLimit',
CERT_PATH = 'certPath',
}
22 changes: 9 additions & 13 deletions src/lib/utils/snapshotAutoUpdater.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,28 @@
export default class SnapshotAutoUpdater {
static _worker: number | undefined;
private static _intervalId: number | undefined;

static schedule(
interval: number,
checkSnapshot: () => Promise<boolean>,
success?: (updated: boolean) => void,
reject?: (err: Error) => void,
success: (updated: boolean) => void = () => {},
reject: (err: Error) => void = () => {},
) {
if (this._worker) {
if (this._intervalId) {
this.terminate();
}

this._worker = setInterval(async () => {
this._intervalId = setInterval(async () => {
try {
const updated = await checkSnapshot();
if (success) {
success(updated);
}
success(updated);
} catch (err) {
if (reject) {
this.terminate();
reject(err);
}
this.terminate();
reject(err);
}
}, interval * 1000);
}

static terminate() {
clearInterval(this._worker);
clearInterval(this._intervalId);
}
}
16 changes: 8 additions & 8 deletions src/switcher-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
DEFAULT_REGEX_MAX_BLACKLISTED,
DEFAULT_REGEX_MAX_TIME_LIMIT,
DEFAULT_TEST_MODE,
SWITCHER_OPTIONS,
} from './lib/constants.ts';

/**
Expand Down Expand Up @@ -69,15 +70,15 @@ export class Switcher {
}

private static buildOptions(options: SwitcherOptions) {
if ('certPath' in options && options.certPath) {
if (SWITCHER_OPTIONS.CERT_PATH in options && options.certPath) {
services.setCerts(options.certPath);
}

if ('silentMode' in options && options.silentMode) {
if (SWITCHER_OPTIONS.SILENT_MODE in options && options.silentMode) {
this._initSilentMode(options.silentMode);
}

if ('snapshotAutoUpdateInterval' in options) {
if (SWITCHER_OPTIONS.SNAPSHOT_AUTO_UPDATE_INTERVAL in options) {
this._options.snapshotAutoUpdateInterval = options.snapshotAutoUpdateInterval;
this.scheduleSnapshotAutoUpdate();
}
Expand Down Expand Up @@ -296,15 +297,15 @@ export class Switcher {
}

private static _initTimedMatch(options: SwitcherOptions) {
if ('regexMaxBlackList' in options) {
if (SWITCHER_OPTIONS.REGEX_MAX_BLACK_LIST in options) {
TimedMatch.setMaxBlackListed(options.regexMaxBlackList || DEFAULT_REGEX_MAX_BLACKLISTED);
}

if ('regexMaxTimeLimit' in options) {
if (SWITCHER_OPTIONS.REGEX_MAX_TIME_LIMIT in options) {
TimedMatch.setMaxTimeLimit(options.regexMaxTimeLimit || DEFAULT_REGEX_MAX_TIME_LIMIT);
}

const hasRegexSafeOption = 'regexSafe' in options;
const hasRegexSafeOption = SWITCHER_OPTIONS.REGEX_SAFE in options;
if (!hasRegexSafeOption || (hasRegexSafeOption && options.regexSafe)) {
TimedMatch.initializeWorker();
}
Expand Down Expand Up @@ -572,8 +573,7 @@ export class Switcher {
}

_useSync() {
return this._delay == 0 ||
!ExecutionLogger.getExecution(this._key, this._input);
return this._delay == 0 || !ExecutionLogger.getExecution(this._key, this._input);
}

get key() {
Expand Down
44 changes: 36 additions & 8 deletions test/playground/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const apiKey = 'JDJiJDA4JEFweTZjSTR2bE9pUjNJOUYvRy9raC4vRS80Q2tzUnk1d3o1aXFmS2o5
const domain = 'Playground';
const component = 'switcher-playground';
const environment = 'default';
const url = 'https://switcherapi.com/api';
const url = 'https://api.switcherapi.com';
const snapshotLocation = './snapshot/';

let switcher: Switcher;
Expand All @@ -15,11 +15,39 @@ let switcher: Switcher;
*/
async function setupSwitcher(local: boolean) {
Switcher.buildContext({ url, apiKey, domain, component, environment }, { local, logger: true });
await Switcher.loadSnapshot(false, true)
.then(() => console.log('Snapshot loaded'))
await Switcher.loadSnapshot(false, local)
.then(version => console.log('Snapshot loaded - version:', version))
.catch(() => console.log('Failed to load Snapshot'));
}

/**
* This code snippet is a minimal example of how to configure and use Switcher4Deno locally.
* No remote API account is required.
*
* Snapshot is loaded from file at test/playground/snapshot/local.json
*/
const _testLocal = async () => {
Switcher.buildContext({
domain: 'Local Playground',
environment: 'local'
}, {
snapshotLocation: './snapshot/',
local: true
});

await Switcher.loadSnapshot()
.then(version => console.log('Snapshot loaded - version:', version))
.catch(() => console.log('Failed to load Snapshot'));

switcher = Switcher.factory();

setInterval(async () => {
const time = Date.now();
const result = await switcher.isItOn(SWITCHER_KEY);
console.log(`- ${Date.now() - time} ms - ${result}`);
}, 1000);
};

// Requires remote API
const _testSimpleAPICall = async (local: boolean) => {
await setupSwitcher(local);
Expand All @@ -30,12 +58,11 @@ const _testSimpleAPICall = async (local: boolean) => {

switcher = Switcher.factory();

while(true) {
setInterval(async () => {
const time = Date.now();
const result = await switcher.isItOn(SWITCHER_KEY);
console.log(`- ${Date.now() - time} ms - ${result}`);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}, 1000);
};

// Requires remote API
Expand All @@ -47,8 +74,9 @@ const _testThrottledAPICall = async () => {
switcher = Switcher.factory();
switcher.throttle(1000);

for (let index = 0; index < 10; index++)
for (let index = 0; index < 10; index++) {
console.log(`Call #${index} - ${await switcher.isItOn(SWITCHER_KEY, [checkNumeric('1')])}}`);
}

Switcher.unloadSnapshot();
};
Expand Down Expand Up @@ -129,4 +157,4 @@ const _testSnapshotAutoUpdate = async () => {
}, 2000);
};

_testSimpleAPICall(true);
_testLocal();
4 changes: 2 additions & 2 deletions test/playground/snapshot/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"data": {
"domain": {
"name": "Playground",
"version": 1656648899029,
"version": 1,
"activated": true,
"group": [
{
Expand All @@ -15,7 +15,7 @@
"strategies": [
{
"strategy": "VALUE_VALIDATION",
"activated": true,
"activated": false,
"operation": "EXIST",
"values": [
"user_1"
Expand Down
22 changes: 22 additions & 0 deletions test/playground/snapshot/local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"data": {
"domain": {
"name": "Local Playground",
"version": 1,
"activated": true,
"group": [
{
"name": "My Features",
"activated": true,
"config": [
{
"key": "MY_SWITCHER",
"activated": true,
"strategies": []
}
]
}
]
}
}
}