-
-
Notifications
You must be signed in to change notification settings - Fork 736
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
Fix/last seen at by environment #4939
Changes from all commits
960a6d1
5e95ffc
93d4ffd
1e65a1a
03c8364
3d4991d
0fe9c75
9a961a7
d93d6a5
766d1e3
83ece07
2407520
8742f5c
7d14af5
98f5629
a474998
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import FakeFeatureToggleStore from '../../../../test/fixtures/fake-feature-toggle-store'; | ||
import FeatureToggleStore from '../../../db/feature-toggle-store'; | ||
import { Db, IUnleashConfig } from '../../../server-impl'; | ||
import { FakeLastSeenStore } from './fake-last-seen-store'; | ||
import { LastSeenService } from './last-seen-service'; | ||
import LastSeenStore from './last-seen-store'; | ||
|
||
export const createLastSeenService = ( | ||
db: Db, | ||
config: IUnleashConfig, | ||
): LastSeenService => { | ||
const lastSeenStore = new LastSeenStore( | ||
db, | ||
config.eventBus, | ||
config.getLogger, | ||
); | ||
|
||
const featureToggleStore = new FeatureToggleStore( | ||
db, | ||
config.eventBus, | ||
config.getLogger, | ||
); | ||
|
||
return new LastSeenService({ lastSeenStore, featureToggleStore }, config); | ||
}; | ||
|
||
export const createFakeLastSeenService = ( | ||
config: IUnleashConfig, | ||
): LastSeenService => { | ||
const lastSeenStore = new FakeLastSeenStore(); | ||
const featureToggleStore = new FakeFeatureToggleStore(); | ||
|
||
return new LastSeenService({ lastSeenStore, featureToggleStore }, config); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { IFeatureLastSeenResults } from './last-seen-read-model'; | ||
import { ILastSeenReadModel } from './types/last-seen-read-model-type'; | ||
|
||
export class FakeLastSeenReadModel implements ILastSeenReadModel { | ||
// eslint-disable-next-line | ||
getForFeature(features: string[]): Promise<IFeatureLastSeenResults> { | ||
return Promise.resolve({}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { LastSeenInput } from './last-seen-service'; | ||
import { ILastSeenStore } from './types/last-seen-store-type'; | ||
|
||
export class FakeLastSeenStore implements ILastSeenStore { | ||
setLastSeen(data: LastSeenInput[]): Promise<void> { | ||
data.map((lastSeen) => lastSeen); | ||
return Promise.resolve(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Logger } from '../../../logger'; | ||
import { IFeatureOverview } from '../../../types'; | ||
import { IFeatureLastSeenResults } from './last-seen-read-model'; | ||
|
||
export class LastSeenMapper { | ||
mapToFeatures( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Map results of reading into environments of incoming features to maintain todays data structure, might change in follow up iteration |
||
features: IFeatureOverview[], | ||
lastSeenAtPerEnvironment: IFeatureLastSeenResults, | ||
logger: Logger, | ||
): IFeatureOverview[] { | ||
return features.map((feature) => { | ||
if (!feature.environments) { | ||
logger.warn('Feature without environments:', feature); | ||
return feature; | ||
} | ||
|
||
feature.environments = feature.environments.map((environment) => { | ||
const noData = | ||
!lastSeenAtPerEnvironment[feature.name] || | ||
!lastSeenAtPerEnvironment[feature.name][environment.name]; | ||
|
||
if (noData) { | ||
logger.warn( | ||
'No last seen data for environment:', | ||
environment, | ||
); | ||
return environment; | ||
} | ||
|
||
environment.lastSeenAt = new Date( | ||
lastSeenAtPerEnvironment[feature.name][environment.name] | ||
.lastSeen, | ||
); | ||
return environment; | ||
}); | ||
return feature; | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Db } from '../../../db/db'; | ||
import { ILastSeenReadModel } from './types/last-seen-read-model-type'; | ||
|
||
const TABLE = 'last_seen_at_metrics'; | ||
|
||
export interface IFeatureLastSeenResults { | ||
[featureName: string]: { | ||
[environment: string]: { | ||
lastSeen: string; | ||
}; | ||
}; | ||
} | ||
export class LastSeenAtReadModel implements ILastSeenReadModel { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. retrieve last seen at results per environment for an array of features |
||
private db: Db; | ||
|
||
constructor(db: Db) { | ||
this.db = db; | ||
} | ||
|
||
async getForFeature(features: string[]): Promise<IFeatureLastSeenResults> { | ||
const rows = await this.db(TABLE).whereIn('feature_name', features); | ||
|
||
const result = rows.reduce((acc, curr) => { | ||
if (!acc[curr.feature_name]) { | ||
acc[curr.feature_name] = {}; | ||
|
||
acc[curr.feature_name][curr.environment] = { | ||
lastSeen: curr.last_seen_at, | ||
}; | ||
} else { | ||
acc[curr.feature_name][curr.environment] = { | ||
lastSeen: curr.last_seen_at, | ||
}; | ||
} | ||
|
||
return acc; | ||
}, {}); | ||
|
||
return result; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
import { secondsToMilliseconds } from 'date-fns'; | ||
import { Logger } from '../../logger'; | ||
import { IUnleashConfig } from '../../server-impl'; | ||
import { IUnleashStores } from '../../types'; | ||
import { IClientMetricsEnv } from '../../types/stores/client-metrics-store-v2'; | ||
import { IFeatureToggleStore } from '../../types/stores/feature-toggle-store'; | ||
import { Logger } from '../../../logger'; | ||
import { IUnleashConfig } from '../../../server-impl'; | ||
import { IClientMetricsEnv } from '../../../types/stores/client-metrics-store-v2'; | ||
import { ILastSeenStore } from './types/last-seen-store-type'; | ||
import { IFeatureToggleStore, IUnleashStores } from '../../../../lib/types'; | ||
|
||
export type LastSeenInput = { | ||
featureName: string; | ||
|
@@ -17,17 +17,26 @@ export class LastSeenService { | |
|
||
private logger: Logger; | ||
|
||
private lastSeenStore: ILastSeenStore; | ||
|
||
private featureToggleStore: IFeatureToggleStore; | ||
|
||
private config: IUnleashConfig; | ||
|
||
constructor( | ||
{ featureToggleStore }: Pick<IUnleashStores, 'featureToggleStore'>, | ||
{ | ||
featureToggleStore, | ||
lastSeenStore, | ||
}: Pick<IUnleashStores, 'featureToggleStore' | 'lastSeenStore'>, | ||
config: IUnleashConfig, | ||
lastSeenInterval = secondsToMilliseconds(30), | ||
) { | ||
this.lastSeenStore = lastSeenStore; | ||
this.featureToggleStore = featureToggleStore; | ||
this.logger = config.getLogger( | ||
'/services/client-metrics/last-seen-service.ts', | ||
); | ||
this.config = config; | ||
|
||
this.timers.push( | ||
setInterval(() => this.store(), lastSeenInterval).unref(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this be part of the scheduler? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will look into separating this in a follow-up |
||
|
@@ -42,7 +51,12 @@ export class LastSeenService { | |
this.logger.debug( | ||
`Updating last seen for ${lastSeenToggles.length} toggles`, | ||
); | ||
await this.featureToggleStore.setLastSeen(lastSeenToggles); | ||
|
||
if (this.config.flagResolver.isEnabled('useLastSeenRefactor')) { | ||
await this.lastSeenStore.setLastSeen(lastSeenToggles); | ||
} else { | ||
await this.featureToggleStore.setLastSeen(lastSeenToggles); | ||
} | ||
Comment on lines
+55
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maintain previous implementation |
||
} | ||
return count; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use composite root pattern for LastSeenService