Scene: Fixes infinite update loop (#59306)

* Scene: Fixes infinite update loop

* fixed lint issue
This commit is contained in:
Torkel Ödegaard 2022-11-25 14:20:56 +01:00 committed by GitHub
parent 28c390bc90
commit f3f1c5aa32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 36 additions and 27 deletions

View File

@ -7,7 +7,6 @@ import { SceneFlexLayout } from '../components/layout/SceneFlexLayout';
import { SceneTimeRange } from '../core/SceneTimeRange';
import { VariableValueSelectors } from '../variables/components/VariableValueSelectors';
import { SceneVariableSet } from '../variables/sets/SceneVariableSet';
import { ConstantVariable } from '../variables/variants/ConstantVariable';
import { CustomVariable } from '../variables/variants/CustomVariable';
import { DataSourceVariable } from '../variables/variants/DataSourceVariable';
import { TestVariable } from '../variables/variants/TestVariable';
@ -45,37 +44,14 @@ export function getVariablesDemo(): Scene {
text: '',
options: [],
}),
new ConstantVariable({
name: 'constant',
value: 'slow',
}),
new CustomVariable({
name: 'Single Custom',
name: 'custom',
query: 'A : 10,B : 20',
}),
new CustomVariable({
name: 'Multi Custom',
query: 'A : 10,B : 20',
isMulti: true,
}),
new DataSourceVariable({
name: 'DataSource',
name: 'ds',
query: 'testdata',
}),
new DataSourceVariable({
name: 'DataSource',
query: 'prometheus',
}),
new DataSourceVariable({
name: 'DataSource multi',
query: 'prometheus',
isMulti: true,
}),
new DataSourceVariable({
name: 'Datasource w/ regex and using $constant',
query: 'prometheus',
regex: '.*$constant.*',
}),
],
}),
layout: new SceneFlexLayout({

View File

@ -134,4 +134,28 @@ describe('SceneVariableList', () => {
});
});
});
describe('When activated with variables update at the same time', () => {
it('Should not start variables multiple times', async () => {
const A = new TestVariable({ name: 'A', query: 'A.*', value: '', text: '', options: [] });
const B = new TestVariable({ name: 'B', query: 'B.*', value: '', text: '', options: [] });
const scene = new TestScene({
$variables: new SceneVariableSet({ variables: [A, B] }),
});
scene.activate();
// Should start variables
expect(A.state.loading).toBe(true);
expect(B.state.loading).toBe(true);
expect(A.getValueOptionsCount).toBe(1);
// Complete the second one
B.signalUpdateCompleted();
// When B complete should not start another instance of A
expect(A.getValueOptionsCount).toBe(1);
});
});
});

View File

@ -60,6 +60,11 @@ export class SceneVariableSet extends SceneObjectBase<SceneVariableSetState> imp
throw new Error('Variable added to variablesToUpdate but does not have validateAndUpdate');
}
// Ignore it if it's already started
if (this.updating.has(variable)) {
continue;
}
// Wait for variables that has dependencies that also needs updates
if (this.hasDependendencyInUpdateQueue(variable)) {
continue;

View File

@ -23,6 +23,7 @@ export interface TestVariableState extends MultiValueVariableState {
export class TestVariable extends MultiValueVariable<TestVariableState> {
private completeUpdate = new Subject<number>();
public isGettingValues = true;
public getValueOptionsCount = 0;
protected _variableDependency = new VariableDependencyConfig(this, {
statePaths: ['query'],
@ -42,10 +43,12 @@ export class TestVariable extends MultiValueVariable<TestVariableState> {
public getValueOptions(args: VariableGetOptionsArgs): Observable<VariableValueOption[]> {
const { delayMs } = this.state;
this.getValueOptionsCount += 1;
return new Observable<VariableValueOption[]>((observer) => {
this.setState({ loading: true });
this.completeUpdate.subscribe({
const sub = this.completeUpdate.subscribe({
next: () => {
observer.next(this.issueQuery());
},
@ -60,6 +63,7 @@ export class TestVariable extends MultiValueVariable<TestVariableState> {
this.isGettingValues = true;
return () => {
sub.unsubscribe();
clearTimeout(timeout);
this.isGettingValues = false;
};