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

adds streaming-whisper type #166

Merged
merged 4 commits into from
Dec 11, 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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

### High Level

An autoscaler for Jitsi instances (`jibri`, `sip-jibri`, `jigasi`, `JVB`, `nomad`), which are deployed in one of the following ways:
An autoscaler for Jitsi instances (`jibri`, `sip-jibri`, `jigasi`, `JVB`, `nomad`, `whisper`), which are deployed in one of the following ways:
* as a parameterized Nomad batch job
* as an Instance in Oracle Cloud
* as a Droplet in Digital Ocean
* custom deployment model

The autoscaler manages multiple `groups` of instances, each having a `type` (`jibri`, `sip-jibri`, `jigasi`, `JVB`, `nomad`) and being deployed in a specific `cloud` (`oracle`, `digitalocean`, `custom`).
The autoscaler manages multiple `groups` of instances, each having a `type` (`jibri`, `sip-jibri`, `jigasi`, `JVB`, `nomad`, `whisper`) and being deployed in a specific `cloud` (`oracle`, `digitalocean`, `custom`).

The autoscaler knows the Jitsi instances status and communicates with them via the [jitsi-autoscaler-sidecar](https://github.com/jitsi/jitsi-autoscaler-sidecar),
which needs to be co-located on each Jitsi instance. The sidecar periodically checks in with the autoscaler via a REST call and sends its status.
Expand Down
2 changes: 1 addition & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ app.put(
body('options.scaleDownPeriodsCount').optional().isInt({ min: 0 }).withMessage('Value must be positive'),
body('instanceType').custom(async (value) => {
if (!(await validator.supportedInstanceType(value))) {
throw new Error('Instance type not supported. Use jvb, jigasi, nomad, jibri or sip-jibri instead');
throw new Error('Instance type not supported. Use jvb, jigasi, nomad, jibri, whisper or sip-jibri instead');
}
return true;
}),
Expand Down
7 changes: 7 additions & 0 deletions src/autoscaler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ export default class AutoscaleProcessor {
(count < group.scalingOptions.maxDesired && value >= group.scalingOptions.scaleUpThreshold) ||
count < group.scalingOptions.minDesired
);
case 'whisper':
return (
(count < group.scalingOptions.maxDesired && value >= group.scalingOptions.scaleUpThreshold) ||
count < group.scalingOptions.minDesired
);
}
return false;
}
Expand All @@ -221,6 +226,8 @@ export default class AutoscaleProcessor {
case 'JVB':
// in the case of JVB scale down only if value (average stress level) is below threshhold
return count > group.scalingOptions.minDesired && value < group.scalingOptions.scaleDownThreshold;
case 'whisper':
return count > group.scalingOptions.minDesired && value < group.scalingOptions.scaleDownThreshold;
}

return false;
Expand Down
13 changes: 13 additions & 0 deletions src/group_report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export default class GroupReportGenerator {
break;
case 'jigasi':
case 'nomad':
case 'whisper':
case 'JVB':
// @TODO: implement JVB instance counting
break;
Expand Down Expand Up @@ -247,6 +248,18 @@ export default class GroupReportGenerator {
instanceReport.scaleStatus = 'GRACEFUL SHUTDOWN';
}
break;
case 'whisper':
instanceReport.scaleStatus = 'ONLINE';
if (instanceState.status.whisperStatus && instanceState.status.whisperStatus.connections) {
instanceReport.scaleStatus = 'IN USE';
}
if (
instanceState.status.whisperStatus &&
instanceState.status.whisperStatus.graceful_shutdown
) {
instanceReport.scaleStatus = 'GRACEFUL SHUTDOWN';
}
break;
}
}
if (instanceState.metadata.name) {
Expand Down
40 changes: 40 additions & 0 deletions src/instance_launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,38 @@ export default class InstanceLauncher {
return listOfInstancesForScaleDown.slice(0, actualScaleDownQuantity);
}

getWhisperForScaleDown(
ctx: Context,
group: InstanceGroup,
unprotectedInstances: InstanceState[],
desiredScaleDownQuantity: number,
): InstanceDetails[] {
// first sort by participant count
unprotectedInstances.sort((a, b) => {
const aConnections = a.status.whisperStatus ? a.status.whisperStatus.connections : 0;
const bConnections = b.status.whisperStatus ? b.status.whisperStatus.connections : 0;
return aConnections - bConnections;
});
const actualScaleDownQuantity = Math.min(desiredScaleDownQuantity, unprotectedInstances.length);
if (actualScaleDownQuantity < desiredScaleDownQuantity) {
ctx.logger.error(
'[Launcher] Nr of whisper instances in group for scale down is less than desired scale down quantity',
{ groupName: group.name, actualScaleDownQuantity, desiredScaleDownQuantity },
);
}
// Try to not scale down the running instances unless needed
// This is needed in case of scale up problems, when we should terminate the provisioning instances first
let listOfInstancesForScaleDown = this.getProvisioningOrWithoutStatusInstances(unprotectedInstances);
if (listOfInstancesForScaleDown.length < actualScaleDownQuantity) {
listOfInstancesForScaleDown = listOfInstancesForScaleDown.concat(
this.getRunningInstances(unprotectedInstances),
);
}

// now return first N instances, least loaded first
return listOfInstancesForScaleDown.slice(0, actualScaleDownQuantity);
}

getJibrisForScaleDown(
ctx: Context,
group: InstanceGroup,
Expand Down Expand Up @@ -365,6 +397,14 @@ export default class InstanceLauncher {
desiredScaleDownQuantity,
);
break;
case 'whisper':
listOfInstancesForScaleDown = this.getWhisperForScaleDown(
ctx,
group,
unprotectedInstances,
desiredScaleDownQuantity,
);
break;
}
return listOfInstancesForScaleDown;
}
Expand Down
7 changes: 7 additions & 0 deletions src/instance_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,19 @@ export interface JVBStatus {
graceful_shutdown: boolean;
}

export interface WhisperStatus {
stress_level: number;
connections: number;
graceful_shutdown: boolean;
}

export interface InstanceStatus {
provisioning: boolean;
jibriStatus?: JibriStatus;
jvbStatus?: JVBStatus;
jigasiStatus?: JigasiStatus;
nomadStatus?: NomadStatus;
whisperStatus?: WhisperStatus;
}

export interface InstanceState {
Expand Down
17 changes: 16 additions & 1 deletion src/instance_tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import InstanceStore, {
JigasiStatus,
JVBStatus,
NomadStatus,
WhisperStatus,
} from './instance_store';

/* eslint-disable */
Expand Down Expand Up @@ -116,6 +117,9 @@ export class InstanceTracker {
case 'JVB':
instanceState.status.jvbStatus = <JVBStatus>report.stats;
break;
case 'whisper':
instanceState.status.whisperStatus = <WhisperStatus>report.stats;
break;
}
}
ctx.logger.debug('Tracking instance state', { instanceState });
Expand Down Expand Up @@ -205,6 +209,14 @@ export class InstanceTracker {
metricValue = state.status.jvbStatus.stress_level;
}
break;
case 'whisper':
if (!state.status.whisperStatus) {
// If whisper is not up or is in graceful shutdown, we should not use it to compute average stress level across the group
trackMetric = false;
} else if (state.status.whisperStatus.stress_level) {
metricValue = state.status.whisperStatus.stress_level;
}
break;
}

if (trackMetric) {
Expand Down Expand Up @@ -236,6 +248,8 @@ export class InstanceTracker {
case 'jigasi':
case 'JVB':
return this.getAverageMetricPerPeriod(ctx, metricInventoryPerPeriod, periodCount);
case 'whisper':
return this.getAverageMetricPerPeriod(ctx, metricInventoryPerPeriod, periodCount);
}
return;
}
Expand Down Expand Up @@ -435,11 +449,12 @@ export class InstanceTracker {
let shutdownStatus = false;
shutdownStatus = state.shutdownStatus;
if (!shutdownStatus) {
// check whether jigasi or JVB reports graceful shutdown, treat as if sidecar has acknowledge shutdown command
// check whether jigasi, JVB or whisper reports graceful shutdown, treat as if sidecar has acknowledge shutdown command
if (
state.status &&
((state.status.jvbStatus && state.status.jvbStatus.graceful_shutdown) ||
(state.status.jigasiStatus && state.status.jigasiStatus.graceful_shutdown) ||
(state.status.whisperStatus && state.status.whisperStatus.graceful_shutdown) ||
(state.status.nomadStatus && !state.status.nomadStatus.eligibleForScheduling))
) {
shutdownStatus = true;
Expand Down
1 change: 1 addition & 0 deletions src/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default class Validator {
instanceType.toLowerCase() == 'sip-jibri' ||
instanceType.toLowerCase() == 'jigasi' ||
instanceType.toLowerCase() == 'nomad' ||
instanceType.toLowerCase() == 'whisper' ||
instanceType.toLowerCase() == 'jvb')
);
}
Expand Down
Loading