Skip to content

Commit

Permalink
Optimize query; add update button
Browse files Browse the repository at this point in the history
  • Loading branch information
dgieselaar authored and ogupte committed Jan 9, 2020
1 parent 6658fbc commit 8a987ea
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 163 deletions.
213 changes: 108 additions & 105 deletions x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import datemath from '@elastic/datemath';
import theme from '@elastic/eui/dist/eui_theme_light.json';
import React, { useMemo, useEffect, useState, useRef } from 'react';
import { find } from 'lodash';
import { i18n } from '@kbn/i18n';
import { EuiButton } from '@elastic/eui';
import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public';
import { ServiceMapAPIResponse } from '../../../../server/lib/service_map/get_service_map';
import {
Connection,
Expand All @@ -23,11 +26,30 @@ import { useDeepObjectIdentity } from '../../../hooks/useDeepObjectIdentity';
import { getAPMHref } from '../../shared/Links/apm/APMLink';
import { useLocation } from '../../../hooks/useLocation';
import { LoadingOverlay } from './LoadingOverlay';
import { useApmPluginContext } from '../../../hooks/useApmPluginContext';

interface ServiceMapProps {
serviceName?: string;
}

type Element =
| {
group: 'nodes';
data: {
id: string;
agentName?: string;
href?: string;
};
}
| {
group: 'edges';
data: {
id: string;
source: string;
target: string;
};
};

const cytoscapeDivStyle = {
height: '85vh',
background: `linear-gradient(
Expand Down Expand Up @@ -69,6 +91,11 @@ function getEdgeId(source: ConnectionNode, destination: ConnectionNode) {

export function ServiceMap({ serviceName }: ServiceMapProps) {
const { urlParams, uiFilters } = useUrlParams();
const { notifications } = useApmPluginContext().core;

const [, _setUnusedState] = useState(false);

const forceUpdate = () => _setUnusedState(value => !value);

const callApmApi = useCallApmApi();

Expand All @@ -92,127 +119,55 @@ export function ServiceMap({ serviceName }: ServiceMapProps) {

const { search } = useLocation();

const getNext = (input: { reset?: boolean; after?: string | undefined }) => {
const getNext = async (input: {
reset?: boolean;
after?: string | undefined;
}) => {
const { start, end, uiFilters: strippedUiFilters, ...query } = params;

if (input.reset) {
renderedElements.current = [];
setResponses([]);
}

if (start && end) {
setIsLoading(true);
callApmApi({
pathname: '/api/apm/service-map',
params: {
query: {
...query,
start,
end,
uiFilters: JSON.stringify(strippedUiFilters),
after: input.after
}
}
})
.then(data => {
setResponses(resp => resp.concat(data));
setIsLoading(false);

const shouldGetNext =
responses.length + 1 < MAX_REQUESTS && data.after;

if (shouldGetNext) {
getNext({ after: data.after });
try {
const data = await callApmApi({
pathname: '/api/apm/service-map',
params: {
query: {
...query,
start,
end,
uiFilters: JSON.stringify(strippedUiFilters),
after: input.after
}
}
})
.catch(() => {
setIsLoading(false);
});
}
};
setResponses(resp => resp.concat(data));
setIsLoading(false);

const _getNext = async (input: {
after?: string | undefined;
start?: string;
end?: string;
}) => {
const { uiFilters: strippedUiFilters, ...query } = params;
if (!(input.start && input.end)) {
return;
}
setIsLoading(true);
try {
const data = await callApmApi({
pathname: '/api/apm/service-map',
params: {
query: {
...query,
start: input.start,
end: input.end,
uiFilters: JSON.stringify(strippedUiFilters),
after: input.after
}
}
});
setResponses(resp => resp.concat(data));
setIsLoading(false);
const shouldGetNext = responses.length + 1 < MAX_REQUESTS && data.after;

const shouldGetNext = responses.length + 1 < MAX_REQUESTS && data.after;

if (shouldGetNext) {
percentageLoadedRef.current += 5;
setPercentageLoaded(percentageLoadedRef.current);
await _getNext({ ...input, after: data.after });
if (shouldGetNext) {
percentageLoadedRef.current += 10;
setPercentageLoaded(percentageLoadedRef.current);
await getNext({ after: data.after });
}
} catch (error) {
setIsLoading(false);
}
} catch (error) {
setIsLoading(false);
}
};
const getNextProgressive = async (input: { reset?: boolean }) => {
const { start, end } = params;

if (input.reset) {
setResponses([]);
percentageLoadedRef.current = 5;
setPercentageLoaded(percentageLoadedRef.current);
}

await _getNext({
start: datemath.parse('now-5m')?.toISOString(),
end: datemath.parse('now')?.toISOString()
});
percentageLoadedRef.current = 20;
setPercentageLoaded(percentageLoadedRef.current);
await _getNext({
start: datemath.parse('now-15m')?.toISOString(),
end: datemath.parse('now-5m')?.toISOString(),
after: 'top'
});
percentageLoadedRef.current = 40;
setPercentageLoaded(percentageLoadedRef.current);
await _getNext({
start: datemath.parse('now-30m')?.toISOString(),
end: datemath.parse('now-15m')?.toISOString(),
after: 'top'
});
percentageLoadedRef.current = 60;
useEffect(() => {
percentageLoadedRef.current = 5;
setPercentageLoaded(percentageLoadedRef.current);
await _getNext({
start: datemath.parse('now-1h')?.toISOString(),
end: datemath.parse('now-30m')?.toISOString(),
after: 'top'
getNext({ reset: true }).then(() => {
percentageLoadedRef.current = 100;
setPercentageLoaded(percentageLoadedRef.current);
});
percentageLoadedRef.current = 80;
setPercentageLoaded(percentageLoadedRef.current);
if (start && end) {
await _getNext({ start, end, after: 'top' });
}
percentageLoadedRef.current = 100;
setPercentageLoaded(percentageLoadedRef.current);
};

useEffect(() => {
// getNext({ reset: true });
getNextProgressive({ reset: true });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [params]);

Expand Down Expand Up @@ -322,10 +277,58 @@ export function ServiceMap({ serviceName }: ServiceMapProps) {
license?.isActive &&
(license?.type === 'platinum' || license?.type === 'trial');

const renderedElements = useRef<Element[]>([]);

const openToast = useRef<string | null>(null);

const newData = elements.filter(element => {
return !find(
renderedElements.current,
el => el.data.id === element.data.id
);
});

if (renderedElements.current.length === 0) {
renderedElements.current = elements;
} else if (newData.length && !openToast.current) {
openToast.current = notifications.toasts.add({
title: i18n.translate('xpack.apm.newServiceMapData', {
defaultMessage: `Newly discovered connections are available.`
}),
onClose: () => {
openToast.current = null;
},
toastLifeTimeMs: 24 * 60 * 60 * 1000,
text: toMountPoint(
<EuiButton
onClick={() => {
renderedElements.current = elements;
if (openToast.current) {
notifications.toasts.remove(openToast.current);
}
forceUpdate();
}}
>
{i18n.translate('xpack.apm.updateServiceMap', {
defaultMessage: 'Update map'
})}
</EuiButton>
)
}).id;
}

useEffect(() => {
return () => {
if (openToast.current) {
notifications.toasts.remove(openToast.current);
}
};
}, [notifications.toasts]);

return isValidPlatinumLicense ? (
<LoadingOverlay isLoading={isLoading} percentageLoaded={percentageLoaded}>
<Cytoscape
elements={elements}
elements={renderedElements.current}
serviceName={serviceName}
style={cytoscapeDivStyle}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
*/
import { uniq, find } from 'lodash';
import { Setup } from '../helpers/setup_request';
import { TRACE_ID } from '../../../common/elasticsearch_fieldnames';
import {
TRACE_ID,
PROCESSOR_EVENT
} from '../../../common/elasticsearch_fieldnames';
import {
Connection,
ServiceConnectionNode,
Expand Down Expand Up @@ -35,6 +38,11 @@ export async function getServiceMapFromTraceIds({
query: {
bool: {
filter: [
{
terms: {
[PROCESSOR_EVENT]: ['span', 'transaction']
}
},
{
terms: {
[TRACE_ID]: traceIds
Expand Down
Loading

0 comments on commit 8a987ea

Please sign in to comment.