Skip to content
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: 4 additions & 0 deletions redisinsight/api/src/constants/telemetry-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ export enum TelemetryEvents {
PubSubMessagePublished = 'PUBSUB_MESSAGE_PUBLISHED',
PubSubChannelSubscribed = 'PUBSUB_CHANNEL_SUBSCRIBED',
PubSubChannelUnsubscribed = 'PUBSUB_CHANNEL_UNSUBSCRIBED',

// Bulk Actions
BulkActionsStarted = 'BULK_ACTIONS_STARTED',
BulkActionsStopped = 'BULK_ACTIONS_STOPPED',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { TelemetryEvents } from 'src/constants';
import { TelemetryBaseService } from 'src/modules/shared/services/base/telemetry.base.service';
import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto';
import { RedisError, ReplyError } from 'src/models';
import { IBulkActionOverview } from 'src/modules/bulk-actions/interfaces/bulk-action-overview.interface';

export interface IExecResult {
response: any;
status: CommandExecutionStatus;
error?: RedisError | ReplyError | Error,
}

@Injectable()
export class BulkActionsAnalyticsService extends TelemetryBaseService {
private events: Map<TelemetryEvents, Function> = new Map();

constructor(protected eventEmitter: EventEmitter2) {
super(eventEmitter);
this.events.set(TelemetryEvents.BulkActionsStarted, this.sendActionStarted.bind(this));
this.events.set(TelemetryEvents.BulkActionsStopped, this.sendActionStopped.bind(this));
}

sendActionStarted(overview: IBulkActionOverview): void {
try {
this.sendEvent(
TelemetryEvents.BulkActionsStarted,
{
databaseId: overview.databaseId,
type: overview.type,
duration: overview.duration,
filter: {
match: overview.filter.match === '*' ? '*' : 'PATTERN',
type: overview.filter.type,
},
progress: {
scanned: overview.progress.scanned,
total: overview.progress.total,
},
},
);
} catch (e) {
// continue regardless of error
}
}

sendActionStopped(overview: IBulkActionOverview): void {
try {
this.sendEvent(
TelemetryEvents.BulkActionsStopped,
{
databaseId: overview.databaseId,
type: overview.type,
duration: overview.duration,
filter: {
match: overview.filter.match === '*' ? '*' : 'PATTERN',
type: overview.filter.type,
},
progress: {
scanned: overview.progress.scanned,
total: overview.progress.total,
},
summary: {
processed: overview.summary.processed,
succeed: overview.summary.succeed,
failed: overview.summary.failed,
},
},
);
} catch (e) {
// continue regardless of error
}
}

getEventsEmitters(): Map<TelemetryEvents, Function> {
return this.events;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { BulkActionsService } from 'src/modules/bulk-actions/bulk-actions.servic
import { BulkActionsProvider } from 'src/modules/bulk-actions/providers/bulk-actions.provider';
import { BulkActionsGateway } from 'src/modules/bulk-actions/bulk-actions.gateway';
import { SharedModule } from 'src/modules/shared/shared.module';
import { BulkActionsAnalyticsService } from 'src/modules/bulk-actions/bulk-actions-analytics.service';

@Module({
imports: [
Expand All @@ -12,6 +13,7 @@ import { SharedModule } from 'src/modules/shared/shared.module';
BulkActionsGateway,
BulkActionsService,
BulkActionsProvider,
BulkActionsAnalyticsService,
],
})
export class BulkActionsModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CreateBulkActionDto } from 'src/modules/bulk-actions/dto/create-bulk-ac
import { BulkActionFilter } from 'src/modules/bulk-actions/models/bulk-action-filter';
import { BulkAction } from 'src/modules/bulk-actions/models/bulk-action';
import { BulkActionsService } from 'src/modules/bulk-actions/bulk-actions.service';
import { BulkActionsAnalyticsService } from 'src/modules/bulk-actions/bulk-actions-analytics.service';

export const mockSocket1 = new MockedSocket();
mockSocket1.id = '1';
Expand Down Expand Up @@ -38,6 +39,7 @@ const mockCreateBulkActionDto = Object.assign(new CreateBulkActionDto(), {

const mockBulkAction = new BulkAction(
mockCreateBulkActionDto.id,
mockCreateBulkActionDto.databaseId,
mockCreateBulkActionDto.type,
mockBulkActionFilter,
mockSocket1,
Expand Down Expand Up @@ -65,6 +67,13 @@ describe('BulkActionsService', () => {
abortUsersBulkActions: jest.fn().mockReturnValue(2),
}),
},
{
provide: BulkActionsAnalyticsService,
useFactory: () => ({
sendActionStarted: jest.fn(),
sendActionStopped: jest.fn(),
}),
},
],
}).compile();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
import { Socket } from 'socket.io';
import { Injectable } from '@nestjs/common';
import { BulkActionsProvider } from 'src/modules/bulk-actions/providers/bulk-actions.provider';
import { CreateBulkActionDto } from 'src/modules/bulk-actions/dto/create-bulk-action.dto';
import { BulkActionIdDto } from 'src/modules/bulk-actions/dto/bulk-action-id.dto';
import { Socket } from 'socket.io';
import { BulkActionsAnalyticsService } from 'src/modules/bulk-actions/bulk-actions-analytics.service';

@Injectable()
export class BulkActionsService {
constructor(
private readonly bulkActionsProvider: BulkActionsProvider,
private readonly analyticsService: BulkActionsAnalyticsService,
) {}

async create(dto: CreateBulkActionDto, socket: Socket) {
const bulkAction = await this.bulkActionsProvider.create(dto, socket);
return bulkAction.getOverview();
const overview = bulkAction.getOverview();

this.analyticsService.sendActionStarted(overview);

return overview;
}

async get(dto: BulkActionIdDto) {
Expand All @@ -22,7 +28,11 @@ export class BulkActionsService {

async abort(dto: BulkActionIdDto) {
const bulkAction = await this.bulkActionsProvider.abort(dto.id);
return bulkAction.getOverview();
const overview = bulkAction.getOverview();

this.analyticsService.sendActionStopped(overview);

return overview;
}

disconnect(socketId: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { IBulkActionFilterOverview } from './bulk-action-filter-overview.interfa

export interface IBulkActionOverview {
id: string,
databaseId: string,
duration: number,
type: BulkActionType,
status: BulkActionStatus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ describe('AbstractBulkActionSimpleRunner', () => {

bulkAction = new BulkAction(
mockCreateBulkActionDto.id,
mockCreateBulkActionDto.databaseId,
mockCreateBulkActionDto.type,
mockBulkActionFilter,
mockSocket,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export class BulkAction implements IBulkAction {

private readonly id: string;

private readonly databaseId: string;

private startTime: number = Date.now();

private endTime: number;
Expand All @@ -28,8 +30,9 @@ export class BulkAction implements IBulkAction {

private readonly debounce: Function;

constructor(id, type, filter, socket) {
constructor(id, databaseId, type, filter, socket) {
this.id = id;
this.databaseId = databaseId;
this.type = type;
this.filter = filter;
this.socket = socket;
Expand Down Expand Up @@ -133,6 +136,7 @@ export class BulkAction implements IBulkAction {

return {
id: this.id,
databaseId: this.databaseId,
type: this.type,
duration: (this.endTime || Date.now()) - this.startTime,
status: this.status,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('AbstractBulkActionRunner', () => {
beforeEach(() => {
bulkAction = new BulkAction(
mockCreateBulkActionDto.id,
mockCreateBulkActionDto.databaseId,
mockCreateBulkActionDto.type,
mockBulkActionFilter,
mockSocket,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ describe('AbstractBulkActionSimpleRunner', () => {

bulkAction = new BulkAction(
mockCreateBulkActionDto.id,
mockCreateBulkActionDto.databaseId,
mockCreateBulkActionDto.type,
mockBulkActionFilter,
mockSocket,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const mockCreateBulkActionDto = {

const bulkAction = new BulkAction(
mockCreateBulkActionDto.id,
mockCreateBulkActionDto.databaseId,
mockCreateBulkActionDto.type,
mockBulkActionFilter,
mockSocket,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class BulkActionsProvider {
throw new Error('You already have bulk action with such id');
}

const bulkAction = new BulkAction(dto.id, dto.type, dto.filter, socket);
const bulkAction = new BulkAction(dto.id, dto.databaseId, dto.type, dto.filter, socket);

this.bulkActions.set(dto.id, bulkAction);

Expand Down