mirror of
https://github.com/expo/turtle.git
synced 2026-11-15 09:38:07 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a62d567f0 | ||
|
|
46787a00c4 | ||
|
|
c09b8acf41 | ||
|
|
de772d198b | ||
|
|
9287d1254e | ||
|
|
97977d895f | ||
|
|
30d083ad62 | ||
|
|
a3f01334df | ||
|
|
65f1eea647 | ||
|
|
2a739dc5ab | ||
|
|
201b28e6a8 | ||
|
|
55eaa18fde | ||
|
|
8ba0f61c6f | ||
|
|
b9d0f12cac | ||
|
|
6c2c55b650 | ||
|
|
9e13991f63 | ||
|
|
2b7c7bb3ff |
No files matched your search
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Turtle CLI logo to the project (created by [@zularizal](https://github.com/zularizal))!
|
||||
### Changed
|
||||
- Updated Android shell app for SDK 32 to fix AppAuth issue (https://github.com/expo/expo/pull/4115).
|
||||
- Default value for build timeout to 15 minutes.
|
||||
### Fixed
|
||||
- Generating Android keystore in turtle when one is not passed to turtle-cli (https://github.com/expo/turtle/pull/65).
|
||||
- Upload logs to s3 if build has been canceled or timed out.
|
||||
|
||||
## [0.7.2] - 2019-05-09
|
||||
### Added
|
||||
|
||||
@@ -20,6 +20,7 @@ RUN dpkg --add-architecture i386 && \
|
||||
libc6:i386\
|
||||
libncurses5:i386\
|
||||
libstdc++6:i386\
|
||||
rsync\
|
||||
unzip\
|
||||
yarn\
|
||||
zlib1g:i386\
|
||||
|
||||
@@ -22,7 +22,7 @@ spec:
|
||||
environment: ${NAMESPACE}
|
||||
spec:
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 1800 ## wait 30 minutes for any builds to complete
|
||||
terminationGracePeriodSeconds: 1200 ## wait 20 minutes for any builds to complete
|
||||
tolerations:
|
||||
- key: dedicated
|
||||
operator: Equal
|
||||
@@ -128,6 +128,16 @@ spec:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: api_port
|
||||
- name: DATADOG_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: datadog_api_key
|
||||
- name: DATADOG_APP_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: datadog_app_key
|
||||
# other vars
|
||||
- name: GRADLE_DAEMON_DISABLED
|
||||
value: "1"
|
||||
|
||||
+9
-4
@@ -36,7 +36,11 @@
|
||||
"set-priorities:default": "expenv ts-node -r tsconfig-paths/register --files src/scripts/setConfigurations.ts",
|
||||
"set-priorities:local": "EXPENV_OVERRIDES=local-common,local,local-queue yarn set-priorities:default",
|
||||
"set-priorities:staging": "yarn set-priorities:default",
|
||||
"set-priorities:production": "EXPENV_OVERRIDES=prod yarn set-priorities:default"
|
||||
"set-priorities:production": "EXPENV_OVERRIDES=prod yarn set-priorities:default",
|
||||
"set-replica-count:default": "expenv ts-node -r tsconfig-paths/register --files src/scripts/setReplicaCount.ts | bunyan -o short -l debug",
|
||||
"set-replica-count:local": "EXPENV_OVERRIDES=local-common,local,local-queue yarn set-replica-count:default",
|
||||
"set-replica-count:staging": "yarn set-replica-count:default",
|
||||
"set-replica-count:production": "EXPENV_OVERRIDES=prod yarn set-replica-count:default"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@@ -79,7 +83,7 @@
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/jest": "^23.3.9",
|
||||
"@types/joi": "^13.4.3",
|
||||
"@types/lodash": "^4.14.109",
|
||||
"@types/lodash": "^4.14.129",
|
||||
"@types/progress": "^2.0.1",
|
||||
"@types/raven": "^2.5.1",
|
||||
"@types/request": "^2.47.1",
|
||||
@@ -115,11 +119,12 @@
|
||||
"commander": "^2.15.1",
|
||||
"copy": "^0.3.1",
|
||||
"decompress": "^4.2.0",
|
||||
"dogapi": "^2.8.3",
|
||||
"fs-extra": "^6.0.0",
|
||||
"ioredis": "^3.2.2",
|
||||
"is-semver": "^1.0.8",
|
||||
"joi": "^13.2.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lodash": "^4.17.11",
|
||||
"progress": "^2.0.0",
|
||||
"raven": "^2.6.2",
|
||||
"request": "^2.88.0",
|
||||
@@ -130,7 +135,7 @@
|
||||
"tar": "^4.4.6",
|
||||
"uuid": "^3.2.1",
|
||||
"which": "^1.3.1",
|
||||
"xdl": "53.5.4"
|
||||
"xdl": "53.7.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@expo/traveling-fastlane-darwin": "1.9.4"
|
||||
|
||||
@@ -21,5 +21,6 @@ export API_HOSTNAME="staging.expo.io"
|
||||
export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
|
||||
yarn test:smoke:android
|
||||
@@ -19,6 +19,7 @@ export API_HOSTNAME="staging.expo.io"
|
||||
export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../.. && pwd )"
|
||||
SDK_VERSION=sdk32 $ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
|
||||
|
||||
@@ -21,5 +21,6 @@ export API_HOSTNAME="noop"
|
||||
export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
|
||||
yarn test:unit
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-0cab68670fc50ce1dc16b7d86ca7976870062c39.tar.gz
|
||||
s3://exp-artifacts/android-shell-builder-c4ba6f73ab341afa378732f863e261a10fc71356.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-fc3d020862e0dcae3aae919d7c685a3e141f8255.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-26-db356a09877642d64023af98e4e2e1e632fbe4df.tar.gz
|
||||
@@ -13,3 +13,28 @@ export const TYPE_DIMENSIONS = (type: string) => [
|
||||
{ Name: 'host', Value: config.hostname },
|
||||
],
|
||||
];
|
||||
|
||||
export const PRIORITY_DIMENSIONS = (type: string, priority: string) => [
|
||||
[
|
||||
{ Name: 'env', Value: config.deploymentEnv },
|
||||
{ Name: 'platform', Value: config.platform },
|
||||
{ Name: 'priority', Value: priority },
|
||||
],
|
||||
[
|
||||
{ Name: 'env', Value: config.deploymentEnv },
|
||||
{ Name: 'platform', Value: config.platform },
|
||||
{ Name: 'type', Value: type },
|
||||
],
|
||||
[
|
||||
{ Name: 'env', Value: config.deploymentEnv },
|
||||
{ Name: 'platform', Value: config.platform },
|
||||
{ Name: 'type', Value: type },
|
||||
{ Name: 'priority', Value: priority },
|
||||
],
|
||||
[
|
||||
{ Name: 'env', Value: config.deploymentEnv },
|
||||
{ Name: 'platform', Value: config.platform },
|
||||
{ Name: 'type', Value: type },
|
||||
{ Name: 'host', Value: config.hostname },
|
||||
],
|
||||
];
|
||||
@@ -38,6 +38,7 @@ const buildJobObject = (appJSON: any, { releaseChannel, username, projectDir, pu
|
||||
config: {
|
||||
..._.get(appJSON, 'expo.android.config', {}),
|
||||
releaseChannel,
|
||||
androidPackage: _.get(appJSON, 'expo.android.package'),
|
||||
publicUrl,
|
||||
},
|
||||
id: uuid.v4(),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from 'path';
|
||||
|
||||
import fs from 'fs-extra';
|
||||
import get from 'lodash/get';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import { Credentials } from 'xdl';
|
||||
|
||||
@@ -19,7 +20,14 @@ async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredential
|
||||
credentials.keystorePassword = uuidv4().replace(/-/g, '');
|
||||
credentials.keyPassword = uuidv4().replace(/-/g, '');
|
||||
credentials.keystoreAlias = Buffer.from(jobData.experienceName).toString('base64');
|
||||
const androidPackage = jobData.manifest.android.package;
|
||||
const androidPackage =
|
||||
get(jobData, 'manifest.android.package')
|
||||
|| get(jobData, 'config.androidPackage');
|
||||
if (!androidPackage) {
|
||||
throw new Error(
|
||||
'Android package name is not set in the app manifest (please update app.json if you\'re using turtle-cli).',
|
||||
);
|
||||
}
|
||||
|
||||
await Credentials.Android.createKeystore(
|
||||
{
|
||||
|
||||
+8
-2
@@ -2,7 +2,7 @@ import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import { env, envNum, envOptional, envTransform } from 'turtle/utils/env';
|
||||
import { env, envBoolean, envNum, envOptional, envTransform } from 'turtle/utils/env';
|
||||
|
||||
export default {
|
||||
env: env('NODE_ENV'),
|
||||
@@ -37,6 +37,12 @@ export default {
|
||||
intervalMs: envNum('AWS_CLOUDWATCH_INTERVAL_MS', 30000),
|
||||
namespace: env('AWS_CLOUDWATCH_NAMESPACE', 'Turtle'),
|
||||
},
|
||||
datadog: {
|
||||
disabled: envBoolean('DATADOG_DISABLED', false),
|
||||
apiKey: envOptional('DATADOG_API_KEY'),
|
||||
appKey: envOptional('DATADOG_APP_KEY'),
|
||||
intervalMs: env('DATADOG_INTERVAL_MS', 5 * 60 * 1000),
|
||||
},
|
||||
redis: {
|
||||
url: env('REDIS_URL'),
|
||||
configUrl: env('REDIS_CONFIG_URL'),
|
||||
@@ -64,7 +70,7 @@ export default {
|
||||
(val: string) => env('NODE_ENV') === 'development' && val === '1',
|
||||
),
|
||||
fakeUpload: envTransform('TURTLE_FAKE_UPLOAD', '0', (val: string) => val === '1'),
|
||||
maxJobTimeMs: envNum('TURTLE_MAX_JOB_TIME_MS', 60 * 60 * 1000),
|
||||
maxJobTimeMs: envNum('TURTLE_MAX_JOB_TIME_MS', 15 * 60 * 1000),
|
||||
useLocalWorkingDir: envTransform('TURTLE_USE_LOCAL_WORKING_DIR', '0', (val: string) => val === '1'),
|
||||
},
|
||||
directories: {
|
||||
|
||||
@@ -12,6 +12,8 @@ export interface IJob {
|
||||
// ios
|
||||
buildType?: IOS.BUILD_TYPES;
|
||||
bundleIdentifier?: string;
|
||||
// android
|
||||
androidPackage?: string;
|
||||
};
|
||||
credentials: {
|
||||
// android
|
||||
|
||||
+4
-3
@@ -76,10 +76,10 @@ async function processJob(jobData: any) {
|
||||
const buildType = _.get(job, 'config.buildType', 'default');
|
||||
try {
|
||||
const status = await build(job);
|
||||
buildStatusMetric.add(buildType, status);
|
||||
buildStatusMetric.add(buildType, priority, status);
|
||||
buildFailed = !status;
|
||||
} catch (err) {
|
||||
buildStatusMetric.add(buildType, false);
|
||||
buildStatusMetric.add(buildType, priority, false);
|
||||
buildFailed = true;
|
||||
throw err;
|
||||
} finally {
|
||||
@@ -113,7 +113,8 @@ function failAfterMaxJobTime(priority: string, receiptHandle: string, job: any)
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, { turtleVersion });
|
||||
await deleteMessage(priority, receiptHandle);
|
||||
} finally {
|
||||
logger.error('Going to terminate turtle agent, just in case...');
|
||||
logger.error('Build timed out. Going to terminate turtle agent.');
|
||||
await logger.cleanup();
|
||||
process.exit(1);
|
||||
}
|
||||
}, config.builder.maxJobTimeMs);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as cloudwatch from 'turtle/aws/cloudwatch';
|
||||
import { TYPE_DIMENSIONS } from 'turtle/aws/cloudwatch/dimensions';
|
||||
import { PRIORITY_DIMENSIONS } from 'turtle/aws/cloudwatch/dimensions';
|
||||
import * as reducers from 'turtle/aws/cloudwatch/reducers';
|
||||
import config from 'turtle/config';
|
||||
import logger from 'turtle/logger';
|
||||
@@ -24,11 +24,11 @@ export function register() {
|
||||
});
|
||||
}
|
||||
|
||||
export function add(type: string, success = true) {
|
||||
export function add(type: string, priority: string, success = true) {
|
||||
cloudwatch.addMetricData({
|
||||
name: BUILD_METRIC_NAME,
|
||||
value: 1,
|
||||
success,
|
||||
extraDimensions: TYPE_DIMENSIONS(type),
|
||||
extraDimensions: PRIORITY_DIMENSIONS(type, priority),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import mapValues from 'lodash/mapValues';
|
||||
import take from 'lodash/take';
|
||||
|
||||
import logger from 'turtle/logger';
|
||||
import { sendMetric } from 'turtle/metrics/datadog';
|
||||
import { getReplicaCount } from 'turtle/utils/metadata';
|
||||
import { getLabeledConfiguration, TurtleModeLabels } from 'turtle/utils/priorities';
|
||||
|
||||
const createMetricName = () => `turtle.replicaCount`;
|
||||
const createModeMetricName = (mode: TurtleModeLabels) => `${createMetricName()}.${mode}`;
|
||||
const createModeTag = (mode: TurtleModeLabels) => `mode:${mode}`;
|
||||
|
||||
export default async function sendConfigToDatadog() {
|
||||
const configuration = await getLabeledConfiguration();
|
||||
const replicaCount = await getReplicaCount();
|
||||
const currentReplicaCount = replicaCount === null ? configuration.length : replicaCount;
|
||||
|
||||
const replicaCounts = mapValues(
|
||||
groupBy<string>(take(configuration, currentReplicaCount)),
|
||||
(i) => i.length,
|
||||
);
|
||||
|
||||
const metricName = createMetricName();
|
||||
|
||||
const normalReplicaCount = replicaCounts[TurtleModeLabels.Normal] || 0;
|
||||
const highReplicaCount = replicaCounts[TurtleModeLabels.High] || 0;
|
||||
const highOnlyReplicaCount = replicaCounts[TurtleModeLabels.HighOnly] || 0;
|
||||
|
||||
const normalTag = createModeTag(TurtleModeLabels.Normal);
|
||||
const normalMetricName = createModeMetricName(TurtleModeLabels.Normal);
|
||||
logger.debug(
|
||||
`Sending ${metricName}=${normalReplicaCount} (${normalTag}), ${normalMetricName}=${normalReplicaCount} to Datadog`,
|
||||
);
|
||||
await sendMetric(metricName, normalReplicaCount, [normalTag]);
|
||||
await sendMetric(normalMetricName, normalReplicaCount);
|
||||
|
||||
const highTag = createModeTag(TurtleModeLabels.High);
|
||||
const highMetricName = createModeMetricName(TurtleModeLabels.High);
|
||||
logger.debug(
|
||||
`Sending ${metricName}=${highReplicaCount} (${highTag}), ${highMetricName}=${highReplicaCount} to Datadog`,
|
||||
);
|
||||
await sendMetric(metricName, highReplicaCount, [highTag]);
|
||||
await sendMetric(highMetricName, highReplicaCount);
|
||||
|
||||
const highOnlyTag = createModeTag(TurtleModeLabels.HighOnly);
|
||||
const highOnlyMetricName = createModeMetricName(TurtleModeLabels.HighOnly);
|
||||
logger.debug(
|
||||
`Sending ${metricName}=${highOnlyReplicaCount} (${highOnlyTag}),`
|
||||
+ ` ${highOnlyMetricName}=${highOnlyReplicaCount} to Datadog`,
|
||||
);
|
||||
await sendMetric(metricName, highOnlyReplicaCount, [highOnlyTag]);
|
||||
await sendMetric(highOnlyMetricName, highOnlyReplicaCount);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import dogapi from 'dogapi';
|
||||
import util from 'util';
|
||||
|
||||
import config from 'turtle/config';
|
||||
|
||||
const datadogSendMetric = util.promisify(dogapi.metric.send);
|
||||
|
||||
if (!config.datadog.disabled) {
|
||||
dogapi.initialize({
|
||||
api_key: config.datadog.apiKey,
|
||||
app_key: config.datadog.appKey,
|
||||
});
|
||||
}
|
||||
|
||||
const tags = [
|
||||
`env:${config.deploymentEnv}`,
|
||||
`platform:${config.platform}`,
|
||||
];
|
||||
|
||||
export function sendMetric(name: string, value: number, additionalTags?: string[]) {
|
||||
if (!config.datadog.disabled) {
|
||||
return datadogSendMetric(name, value, { tags: [...tags, ...(additionalTags || [])] });
|
||||
}
|
||||
}
|
||||
@@ -28,27 +28,33 @@ const TIMEOUT = 3000;
|
||||
|
||||
const AVAILABLE_CONFIGURATIONS_IOS = [
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
// there are 5 iOS builders at the moment
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
];
|
||||
|
||||
const AVAILABLE_CONFIGURATIONS_ANDROID = [
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
// there are 15 Android builders at the moment
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import isNaN from 'lodash/isNaN';
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
import { setReplicaCount } from 'turtle/utils/metadata';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
async function run() {
|
||||
const platform = process.env.SCRIPT_PLATFORM;
|
||||
const replicaCountRaw = process.env.SCRIPT_REPLICA_COUNT;
|
||||
const replicaCount = Number(replicaCountRaw);
|
||||
|
||||
if (!platform || !replicaCountRaw) {
|
||||
throw new Error('You must set both SCRIPT_PLATFORM and SCRIPT_REPLICA_COUNT env variables.');
|
||||
}
|
||||
|
||||
if (!Object.values(PLATFORMS).includes(platform)) {
|
||||
throw new Error(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
|
||||
if (isNaN(replicaCount)) {
|
||||
throw new Error(`Wrong value for replica count: ${replicaCountRaw}`);
|
||||
}
|
||||
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
logger.info(`[${platform}] Setting replica count in redis to ${replicaCount}`);
|
||||
await setReplicaCount(platform as PLATFORMS, replicaCount);
|
||||
redis.disconnect();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run()
|
||||
.then(() => logger.info('All done'))
|
||||
.catch((err) => {
|
||||
logger.error('Error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,23 @@
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import config from 'turtle/config';
|
||||
import logger from 'turtle/logger';
|
||||
import * as metrics from 'turtle/metrics';
|
||||
import sendConfigToDatadog from 'turtle/metrics/buildersConfig';
|
||||
|
||||
export default async function commonSetup() {
|
||||
announceBuildersConfig();
|
||||
await metrics.init();
|
||||
await fs.remove(config.directories.temporaryFilesRoot);
|
||||
await fs.remove(config.directories.tempS3LogsDir);
|
||||
}
|
||||
|
||||
async function announceBuildersConfig() {
|
||||
try {
|
||||
await sendConfigToDatadog();
|
||||
} catch (err) {
|
||||
logger.error({ err }, 'Failed to send metrics to Datadog');
|
||||
} finally {
|
||||
setTimeout(announceBuildersConfig, config.datadog.intervalMs);
|
||||
}
|
||||
}
|
||||
Vendored
+5
-4
@@ -1,9 +1,10 @@
|
||||
declare module 'copy';
|
||||
declare module 'xdl';
|
||||
declare module 'async-retry';
|
||||
declare module 'bunyan';
|
||||
declare module 'bunyan-sentry-stream';
|
||||
declare module 'bunyan-debug-stream';
|
||||
declare module 'async-retry';
|
||||
declare module 'copy';
|
||||
declare module 'dogapi';
|
||||
declare module 'ioredis';
|
||||
declare module 'request-progress';
|
||||
declare module 'is-semver';
|
||||
declare module 'request-progress';
|
||||
declare module 'xdl';
|
||||
@@ -16,5 +16,16 @@ export const env = (varName: string, defaultValue?: any) => {
|
||||
export const envOptional = (varName: string) => env(varName, null);
|
||||
export const envTransform = (varName: string, defaultValue: any, fn: any) => fn(env(varName, defaultValue));
|
||||
export const envNum = (varName: string, defaultValue?: number) => parseInt(env(varName, defaultValue), 10);
|
||||
export const envBoolean = (varName: string, defaultValue?: boolean) => {
|
||||
let defaultString;
|
||||
if (defaultValue === true) {
|
||||
defaultString = 'true';
|
||||
} else if (defaultValue === false) {
|
||||
defaultString = 'false';
|
||||
} else {
|
||||
defaultString = defaultValue;
|
||||
}
|
||||
return env(varName, defaultString) === 'true';
|
||||
};
|
||||
|
||||
const isOffline = () => process.env.TURTLE_MODE === 'offline';
|
||||
@@ -0,0 +1,21 @@
|
||||
import config from 'turtle/config';
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
const createKeyPrefix = (platform: PLATFORMS) => `${config.deploymentEnv}:${platform}`;
|
||||
const createReplicaCountKey = (platform: PLATFORMS) => `${createKeyPrefix(platform)}:replicaCount`;
|
||||
|
||||
export async function setReplicaCount(platform: PLATFORMS, replicaCount: number) {
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
await redis.set(
|
||||
createReplicaCountKey(platform),
|
||||
replicaCount,
|
||||
);
|
||||
}
|
||||
|
||||
export async function getReplicaCount(maybePlatform?: PLATFORMS) {
|
||||
const platform = maybePlatform || config.platform;
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
const result = await redis.get(createReplicaCountKey(platform));
|
||||
return result === null ? null : Number(result);
|
||||
}
|
||||
+26
-1
@@ -1,4 +1,5 @@
|
||||
import Joi from 'joi';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import os from 'os';
|
||||
|
||||
import config from 'turtle/config';
|
||||
@@ -8,6 +9,12 @@ import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
export const NORMAL = 'normalPriority';
|
||||
export const HIGH = 'highPriority';
|
||||
|
||||
export enum TurtleModeLabels {
|
||||
Normal = 'normal',
|
||||
High = 'high',
|
||||
HighOnly = 'highOnly',
|
||||
}
|
||||
|
||||
export const NORMAL_CONFIGURATION = [NORMAL, HIGH];
|
||||
export const HIGH_CONFIGURATION = [HIGH, NORMAL];
|
||||
export const HIGH_ONLY_CONFIGURATION = [HIGH];
|
||||
@@ -56,7 +63,7 @@ export async function getPriorities() {
|
||||
}
|
||||
|
||||
try {
|
||||
const configurations = JSON.parse(await redis.get(createConfigurationsKey()));
|
||||
const configurations = await getConfiguration(redis);
|
||||
const configurationsIndex = await redis.getConfig(createConfigurationsKey(), os.hostname());
|
||||
logger.debug(`Using configuration at index ${configurationsIndex} pulled from redis`);
|
||||
const { error, value: configValue } = configSchema.validate(configurations[configurationsIndex]);
|
||||
@@ -85,3 +92,21 @@ export async function getPriorities() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getConfiguration(currentRedisClient: any) {
|
||||
const redis = currentRedisClient || await getRedisClient(RedisClient.Configuration);
|
||||
return JSON.parse(await redis.get(createConfigurationsKey()));
|
||||
}
|
||||
|
||||
export async function getLabeledConfiguration(currentRedisClient?: any) {
|
||||
const configuration = await getConfiguration(currentRedisClient);
|
||||
return configuration.map((i: string[]) => {
|
||||
if (isEqual(i, NORMAL_CONFIGURATION)) {
|
||||
return TurtleModeLabels.Normal;
|
||||
} else if (isEqual(i, HIGH_CONFIGURATION)) {
|
||||
return TurtleModeLabels.High;
|
||||
} else {
|
||||
return TurtleModeLabels.HighOnly;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -79,6 +79,7 @@ export async function registerListener(jobId: string, deleteMessage: any) {
|
||||
if (message === jobId) {
|
||||
logger.info({ lastBuildLog: true }, 'Job cancelled - killing process');
|
||||
await deleteMessage();
|
||||
await logger.cleanup();
|
||||
setTimeout(() => process.exit(1), MILLIS_TO_UPLOAD_LOGS);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user