Skip to content

Commit

Permalink
[NAN-478] update runner logic to allow to connect to a remote instance (
Browse files Browse the repository at this point in the history
NangoHQ#1768)

## Describe your changes
* Add a remote instance runner so jobs doesn't need to spawn a process.
In some cases I saw that a sync failed because spawning a process took
too long. For enterprise customers they can setup a runner instance and
so in that case jobs will connect to that remote instance instead.
Customers can set this using the `RUNNER_SERVICE_URL` env variable
* Best practice is to use an AWS role for connecting to a bucket so this
update allows customers to configure bucket connection using the role as
long as they have `AWS_REGION` and `AWS_BUCKET_NAME` set

## Issue ticket number and link
NAN-478

## Checklist before requesting a review (skip if just adding/editing
APIs & templates)
- [ ] I added tests, otherwise the reason is: 
- [ ] I added observability, otherwise the reason is:
- [ ] I added analytics, otherwise the reason is:
  • Loading branch information
khaliqgant authored Mar 1, 2024
1 parent d7cf723 commit 7229b49
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 5 deletions.
30 changes: 30 additions & 0 deletions packages/jobs/lib/runner/remote.runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { Runner } from './runner.js';
import { RunnerType } from './runner.js';
import { getRunnerClient } from '@nangohq/nango-runner';

export class RemoteRunner implements Runner {
public client: any;
public runnerType: RunnerType = RunnerType.Remote;
constructor(
public readonly id: string,
public readonly url: string
) {
this.client = getRunnerClient(this.url);
}

async suspend(): Promise<void> {
console.warn('cannot suspend a remote runner');
}

toJSON() {
return { runnerType: this.runnerType, id: this.id, url: this.url };
}

static fromJSON(obj: any): RemoteRunner {
throw new Error(`'fromJSON(${obj})' not implemented`);
}

static async getOrStart(runnerId: string): Promise<RemoteRunner> {
return new RemoteRunner(runnerId, process.env['RUNNER_SERVICE_URL'] || 'http://nango-runner');
}
}
18 changes: 15 additions & 3 deletions packages/jobs/lib/runner/runner.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import type { KVStore } from '@nangohq/shared/lib/utils/kvstore/KVStore.js';
import { LocalRunner } from './local.runner.js';
import { RenderRunner } from './render.runner.js';
import { getEnv, getRedisUrl, InMemoryKVStore, RedisKVStore } from '@nangohq/shared';
import { RemoteRunner } from './remote.runner.js';
import { getEnv, getRedisUrl, InMemoryKVStore, RedisKVStore, isEnterprise } from '@nangohq/shared';
import type { ProxyAppRouter } from '@nangohq/nango-runner';

export enum RunnerType {
Local = 'local',
Render = 'render'
Render = 'render',
Remote = 'remote'
}

export interface Runner {
Expand Down Expand Up @@ -48,7 +50,15 @@ export async function getOrStartRunner(runnerId: string): Promise<Runner> {
} catch (err) {}
}
const isRender = process.env['IS_RENDER'] === 'true';
const runner = isRender ? await RenderRunner.getOrStart(runnerId) : await LocalRunner.getOrStart(runnerId);
let runner: Runner;
if (isEnterprise()) {
runner = await RemoteRunner.getOrStart(runnerId);
} else if (isRender) {
runner = await RenderRunner.getOrStart(runnerId);
} else {
runner = await LocalRunner.getOrStart(runnerId);
}

await waitForRunner(runner);
await runnersCache.set(runner);
return runner;
Expand Down Expand Up @@ -86,6 +96,8 @@ class RunnerCache {
return LocalRunner.fromJSON(obj);
case RunnerType.Render:
return RenderRunner.fromJSON(obj);
case RunnerType.Remote:
return RemoteRunner.fromJSON(obj);
}
}
return undefined;
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/lib/services/file/remote.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import localFileService from './local.service.js';
let client: S3Client | null = null;
let useS3 = !isLocal();

if (isEnterprise() && !(process.env['AWS_PUBLIC_ACCESS_KEY_ID'] && process.env['AWS_PUBLIC_SECRET_ACCESS'])) {
useS3 = false;
if (isEnterprise()) {
useS3 = Boolean(process.env['AWS_REGION'] && process.env['AWS_BUCKET_NAME']);
client = new S3Client({
region: (process.env['AWS_REGION'] as string) || 'us-west-2'
});
Expand Down

0 comments on commit 7229b49

Please sign in to comment.