@webex/plugin-meetings 3.0.0-beta.241 → 3.0.0-beta.243
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +25 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +5 -0
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/meeting/request.js +1 -1
- package/dist/meeting/request.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/metrics/constants.d.ts +2 -0
- package/package.json +19 -19
- package/src/constants.ts +1 -0
- package/src/locus-info/index.ts +33 -2
- package/src/locus-info/parser.ts +7 -0
- package/src/meeting/request.ts +1 -1
- package/src/metrics/constants.ts +2 -0
- package/test/unit/spec/locus-info/index.js +118 -1
package/src/locus-info/index.ts
CHANGED
|
@@ -25,6 +25,8 @@ import ControlsUtils from './controlsUtils';
|
|
|
25
25
|
import EmbeddedAppsUtils from './embeddedAppsUtils';
|
|
26
26
|
import MediaSharesUtils from './mediaSharesUtils';
|
|
27
27
|
import LocusDeltaParser from './parser';
|
|
28
|
+
import Metrics from '../metrics';
|
|
29
|
+
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
28
30
|
|
|
29
31
|
/**
|
|
30
32
|
* @description LocusInfo extends ChildEmitter to convert locusInfo info a private emitter to parent object
|
|
@@ -110,6 +112,37 @@ export default class LocusInfo extends EventsScope {
|
|
|
110
112
|
// return value ignored on purpose
|
|
111
113
|
meeting.meetingRequest
|
|
112
114
|
.getLocusDTO({url})
|
|
115
|
+
.catch((e) => {
|
|
116
|
+
if (isDelta) {
|
|
117
|
+
LoggerProxy.logger.info(
|
|
118
|
+
'Locus-info:index#doLocusSync --> delta sync failed, falling back to full sync'
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.LOCUS_DELTA_SYNC_FAILED, {
|
|
122
|
+
correlationId: meeting.correlationId,
|
|
123
|
+
url,
|
|
124
|
+
reason: e.message,
|
|
125
|
+
errorName: e.name,
|
|
126
|
+
stack: e.stack,
|
|
127
|
+
code: e.code,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
isDelta = false;
|
|
131
|
+
|
|
132
|
+
return meeting.meetingRequest.getLocusDTO({url: meeting.locusUrl}).catch((err) => {
|
|
133
|
+
LoggerProxy.logger.info(
|
|
134
|
+
'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
|
|
135
|
+
);
|
|
136
|
+
this.webex.meetings.destroy(meeting, MEETING_REMOVED_REASON.LOCUS_DTO_SYNC_FAILED);
|
|
137
|
+
throw err;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
LoggerProxy.logger.info(
|
|
141
|
+
'Locus-info:index#doLocusSync --> fallback full sync failed, destroying the meeting'
|
|
142
|
+
);
|
|
143
|
+
this.webex.meetings.destroy(meeting, MEETING_REMOVED_REASON.LOCUS_DTO_SYNC_FAILED);
|
|
144
|
+
throw e;
|
|
145
|
+
})
|
|
113
146
|
.then((res) => {
|
|
114
147
|
if (isDelta) {
|
|
115
148
|
if (!isEmpty(res.body)) {
|
|
@@ -122,8 +155,6 @@ export default class LocusInfo extends EventsScope {
|
|
|
122
155
|
} else {
|
|
123
156
|
meeting.locusInfo.onFullLocus(res.body);
|
|
124
157
|
}
|
|
125
|
-
})
|
|
126
|
-
.finally(() => {
|
|
127
158
|
// Notify parser to resume processing delta events.
|
|
128
159
|
// Any deltas in the queue that have now been superseded by this sync will simply be ignored
|
|
129
160
|
this.locusParser.resume();
|
package/src/locus-info/parser.ts
CHANGED
|
@@ -3,6 +3,9 @@ import {difference} from 'lodash';
|
|
|
3
3
|
import SortedQueue from '../common/queue';
|
|
4
4
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
5
5
|
|
|
6
|
+
import Metrics from '../metrics';
|
|
7
|
+
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
8
|
+
|
|
6
9
|
const MAX_OOO_DELTA_COUNT = 5; // when we receive an out-of-order delta and the queue builds up to MAX_OOO_DELTA_COUNT, we do a sync with Locus
|
|
7
10
|
const OOO_DELTA_WAIT_TIME = 10000; // [ms] minimum wait time before we do a sync if we get out-of-order deltas
|
|
8
11
|
const OOO_DELTA_WAIT_TIME_RANDOM_DELAY = 5000; // [ms] max random delay added to OOO_DELTA_WAIT_TIME
|
|
@@ -293,6 +296,10 @@ export default class Parser {
|
|
|
293
296
|
// the incoming locus has baseSequence from the future, so it is out-of-order,
|
|
294
297
|
// we are missing 1 or more locus that should be in front of it, we need to wait for it
|
|
295
298
|
comparison = WAIT;
|
|
299
|
+
|
|
300
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.LOCUS_DELTA_OUT_OF_ORDER, {
|
|
301
|
+
stack: new Error().stack,
|
|
302
|
+
});
|
|
296
303
|
}
|
|
297
304
|
break;
|
|
298
305
|
default:
|
package/src/meeting/request.ts
CHANGED
package/src/metrics/constants.ts
CHANGED
|
@@ -55,6 +55,8 @@ const BEHAVIORAL_METRICS = {
|
|
|
55
55
|
MOVE_FROM_FAILURE: 'js_sdk_move_from_failure',
|
|
56
56
|
TURN_DISCOVERY_FAILURE: 'js_sdk_turn_discovery_failure',
|
|
57
57
|
MEETING_INFO_POLICY_ERROR: 'js_sdk_meeting_info_policy_error',
|
|
58
|
+
LOCUS_DELTA_SYNC_FAILED: 'js_sdk_locus_delta_sync_failed',
|
|
59
|
+
LOCUS_DELTA_OUT_OF_ORDER: 'js_sdk_locus_delta_ooo',
|
|
58
60
|
};
|
|
59
61
|
|
|
60
62
|
export {BEHAVIORAL_METRICS as default};
|
|
@@ -10,6 +10,7 @@ import SelfUtils from '@webex/plugin-meetings/src/locus-info/selfUtils';
|
|
|
10
10
|
import InfoUtils from '@webex/plugin-meetings/src/locus-info/infoUtils';
|
|
11
11
|
import EmbeddedAppsUtils from '@webex/plugin-meetings/src/locus-info/embeddedAppsUtils';
|
|
12
12
|
import LocusDeltaParser from '@webex/plugin-meetings/src/locus-info/parser';
|
|
13
|
+
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
13
14
|
|
|
14
15
|
import {
|
|
15
16
|
LOCUSINFO,
|
|
@@ -24,7 +25,6 @@ import {
|
|
|
24
25
|
} from '../../../../src/constants';
|
|
25
26
|
|
|
26
27
|
import {self, selfWithInactivity} from './selfConstant';
|
|
27
|
-
import uuid from 'uuid';
|
|
28
28
|
|
|
29
29
|
describe('plugin-meetings', () => {
|
|
30
30
|
describe('LocusInfo index', () => {
|
|
@@ -39,6 +39,7 @@ describe('plugin-meetings', () => {
|
|
|
39
39
|
const locus = {};
|
|
40
40
|
const meetingId = 'meetingId';
|
|
41
41
|
let locusInfo;
|
|
42
|
+
let sendBehavioralMetricStub;
|
|
42
43
|
|
|
43
44
|
const webex = new MockWebex({
|
|
44
45
|
children: {
|
|
@@ -65,6 +66,12 @@ describe('plugin-meetings', () => {
|
|
|
65
66
|
},
|
|
66
67
|
},
|
|
67
68
|
};
|
|
69
|
+
|
|
70
|
+
sendBehavioralMetricStub = sinon.stub(Metrics, 'sendBehavioralMetric');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
afterEach(() => {
|
|
74
|
+
sinon.restore();
|
|
68
75
|
});
|
|
69
76
|
|
|
70
77
|
describe('#updateControls', () => {
|
|
@@ -1877,6 +1884,114 @@ describe('plugin-meetings', () => {
|
|
|
1877
1884
|
});
|
|
1878
1885
|
});
|
|
1879
1886
|
|
|
1887
|
+
describe('edge cases for sync failing', () => {
|
|
1888
|
+
const {DESYNC} = LocusDeltaParser.loci;
|
|
1889
|
+
const fakeFullLocusDto = {id: 'fake full locus dto'};
|
|
1890
|
+
let meeting;
|
|
1891
|
+
|
|
1892
|
+
beforeEach(() => {
|
|
1893
|
+
sinon.stub(locusInfo.locusParser, 'resume');
|
|
1894
|
+
sinon.stub(webex.meetings, 'destroy');
|
|
1895
|
+
|
|
1896
|
+
meeting = {
|
|
1897
|
+
meetingRequest: {
|
|
1898
|
+
getLocusDTO: sandbox.stub(),
|
|
1899
|
+
},
|
|
1900
|
+
locusInfo: {
|
|
1901
|
+
handleLocusDelta: sandbox.stub(),
|
|
1902
|
+
onFullLocus: sandbox.stub(),
|
|
1903
|
+
},
|
|
1904
|
+
locusUrl: 'fullSyncUrl',
|
|
1905
|
+
};
|
|
1906
|
+
|
|
1907
|
+
locusInfo.locusParser.workingCopy = {
|
|
1908
|
+
syncUrl: 'deltaSyncUrl',
|
|
1909
|
+
};
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
it('applyLocusDeltaData gets full locus on DESYNC action if we do not have a syncUrl and destroys the meeting if that fails', () => {
|
|
1913
|
+
meeting.meetingRequest.getLocusDTO.rejects(new Error('fake error'));
|
|
1914
|
+
|
|
1915
|
+
locusInfo.locusParser.workingCopy = {}; // no syncUrl
|
|
1916
|
+
|
|
1917
|
+
// Since we have a promise inside a function we want to test that's not returned,
|
|
1918
|
+
// we will wait and stub it's last function to resolve this waiting promise.
|
|
1919
|
+
return new Promise((resolve) => {
|
|
1920
|
+
webex.meetings.destroy.callsFake(() => resolve());
|
|
1921
|
+
locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
|
|
1922
|
+
}).then(() => {
|
|
1923
|
+
assert.calledOnceWithExactly(meeting.meetingRequest.getLocusDTO, {url: 'fullSyncUrl'});
|
|
1924
|
+
|
|
1925
|
+
assert.notCalled(meeting.locusInfo.handleLocusDelta);
|
|
1926
|
+
assert.notCalled(meeting.locusInfo.onFullLocus);
|
|
1927
|
+
assert.notCalled(locusInfo.locusParser.resume);
|
|
1928
|
+
|
|
1929
|
+
assert.calledOnceWithExactly(webex.meetings.destroy, meeting, 'LOCUS_DTO_SYNC_FAILED');
|
|
1930
|
+
});
|
|
1931
|
+
});
|
|
1932
|
+
|
|
1933
|
+
it('applyLocusDeltaData first tries a delta sync on DESYNC action and if that fails, does a full locus sync', () => {
|
|
1934
|
+
meeting.meetingRequest.getLocusDTO.onCall(0).rejects(new Error('fake error'));
|
|
1935
|
+
meeting.meetingRequest.getLocusDTO.onCall(1).resolves({body: fakeFullLocusDto});
|
|
1936
|
+
|
|
1937
|
+
// Since we have a promise inside a function we want to test that's not returned,
|
|
1938
|
+
// we will wait and stub it's last function to resolve this waiting promise.
|
|
1939
|
+
return new Promise((resolve) => {
|
|
1940
|
+
locusInfo.locusParser.resume.callsFake(() => resolve());
|
|
1941
|
+
locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
|
|
1942
|
+
}).then(() => {
|
|
1943
|
+
assert.calledTwice(meeting.meetingRequest.getLocusDTO);
|
|
1944
|
+
|
|
1945
|
+
assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[0].args, [{url: 'deltaSyncUrl'}]);
|
|
1946
|
+
assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[1].args, [{url: 'fullSyncUrl'}]);
|
|
1947
|
+
|
|
1948
|
+
assert.calledWith(sendBehavioralMetricStub, 'js_sdk_locus_delta_sync_failed', {
|
|
1949
|
+
correlationId: meeting.correlationId,
|
|
1950
|
+
url: 'deltaSyncUrl',
|
|
1951
|
+
reason: 'fake error',
|
|
1952
|
+
errorName: 'Error',
|
|
1953
|
+
stack: sinon.match.any,
|
|
1954
|
+
code: sinon.match.any,
|
|
1955
|
+
});
|
|
1956
|
+
|
|
1957
|
+
assert.notCalled(meeting.locusInfo.handleLocusDelta);
|
|
1958
|
+
assert.calledOnceWithExactly(meeting.locusInfo.onFullLocus, fakeFullLocusDto);
|
|
1959
|
+
assert.calledOnce(locusInfo.locusParser.resume);
|
|
1960
|
+
});
|
|
1961
|
+
});
|
|
1962
|
+
|
|
1963
|
+
it('applyLocusDeltaData destroys the meeting if both delta sync and full sync fail', () => {
|
|
1964
|
+
meeting.meetingRequest.getLocusDTO.rejects(new Error('fake error'));
|
|
1965
|
+
|
|
1966
|
+
// Since we have a promise inside a function we want to test that's not returned,
|
|
1967
|
+
// we will wait and stub it's last function to resolve this waiting promise.
|
|
1968
|
+
return new Promise((resolve) => {
|
|
1969
|
+
webex.meetings.destroy.callsFake(() => resolve());
|
|
1970
|
+
locusInfo.applyLocusDeltaData(DESYNC, fakeLocus, meeting);
|
|
1971
|
+
}).then(() => {
|
|
1972
|
+
assert.calledTwice(meeting.meetingRequest.getLocusDTO);
|
|
1973
|
+
|
|
1974
|
+
assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[0].args, [{url: 'deltaSyncUrl'}]);
|
|
1975
|
+
assert.deepEqual(meeting.meetingRequest.getLocusDTO.getCalls()[1].args, [{url: 'fullSyncUrl'}]);
|
|
1976
|
+
|
|
1977
|
+
assert.calledWith(sendBehavioralMetricStub, 'js_sdk_locus_delta_sync_failed', {
|
|
1978
|
+
correlationId: meeting.correlationId,
|
|
1979
|
+
url: 'deltaSyncUrl',
|
|
1980
|
+
reason: 'fake error',
|
|
1981
|
+
errorName: 'Error',
|
|
1982
|
+
stack: sinon.match.any,
|
|
1983
|
+
code: sinon.match.any,
|
|
1984
|
+
});
|
|
1985
|
+
|
|
1986
|
+
assert.notCalled(meeting.locusInfo.handleLocusDelta);
|
|
1987
|
+
assert.notCalled(meeting.locusInfo.onFullLocus);
|
|
1988
|
+
assert.notCalled(locusInfo.locusParser.resume);
|
|
1989
|
+
|
|
1990
|
+
assert.calledOnceWithExactly(webex.meetings.destroy, meeting, 'LOCUS_DTO_SYNC_FAILED');
|
|
1991
|
+
});
|
|
1992
|
+
});
|
|
1993
|
+
});
|
|
1994
|
+
|
|
1880
1995
|
it('onDeltaLocus handle delta data', () => {
|
|
1881
1996
|
fakeLocus.participants = {};
|
|
1882
1997
|
const fakeBreakout = {
|
|
@@ -2420,6 +2535,8 @@ describe('plugin-meetings', () => {
|
|
|
2420
2535
|
// send an out-of-order delta
|
|
2421
2536
|
locusInfo.handleLocusDelta(oooDelta, mockMeeting);
|
|
2422
2537
|
|
|
2538
|
+
assert.calledOnceWithExactly(sendBehavioralMetricStub, 'js_sdk_locus_delta_ooo', { stack: sinon.match.any})
|
|
2539
|
+
|
|
2423
2540
|
await clock.tickAsync(12499);
|
|
2424
2541
|
await testUtils.flushPromises();
|
|
2425
2542
|
assert.notCalled(syncRequestStub);
|