Skip to content

Commit 1fe0224

Browse files
authored
feat(webui): Display notification for errors from Presto. (#1188)
1 parent 4216b1e commit 1fe0224

File tree

9 files changed

+80
-27
lines changed

9 files changed

+80
-27
lines changed

components/webui/client/src/pages/SearchPage/SearchControls/Presto/presto-search-requests.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ const handlePrestoQuerySubmit = (payload: PrestoQueryJobCreationSchema) => {
4545
// User should NOT be able to submit a new query while an existing query is in progress.
4646
if (
4747
searchUiState !== SEARCH_UI_STATE.DEFAULT &&
48-
searchUiState !== SEARCH_UI_STATE.DONE
48+
searchUiState !== SEARCH_UI_STATE.DONE &&
49+
searchUiState !== SEARCH_UI_STATE.FAILED
4950
) {
5051
console.error("Cannot submit query while existing query is in progress.");
5152

components/webui/client/src/pages/SearchPage/SearchControls/QueryInput/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ const QueryInput = () => {
5757
return (v ?? 0) + PROGRESS_INCREMENT;
5858
});
5959
}, PROGRESS_INTERVAL_MILLIS);
60-
} else if (searchUiState === SEARCH_UI_STATE.DONE) {
60+
} else if (
61+
searchUiState === SEARCH_UI_STATE.DONE ||
62+
searchUiState === SEARCH_UI_STATE.FAILED
63+
) {
6164
clearInterval(intervalIdRef.current);
6265
intervalIdRef.current = 0;
6366
setPseudoProgress(null);
@@ -72,7 +75,8 @@ const QueryInput = () => {
7275
useEffect(() => {
7376
if (
7477
searchUiState === SEARCH_UI_STATE.DEFAULT ||
75-
searchUiState === SEARCH_UI_STATE.DONE
78+
searchUiState === SEARCH_UI_STATE.DONE ||
79+
searchUiState === SEARCH_UI_STATE.FAILED
7680
) {
7781
inputRef.current?.focus();
7882
}

components/webui/client/src/pages/SearchPage/SearchControls/search-requests.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ const handleQuerySubmit = (payload: QueryJobCreationSchema) => {
5757
// User should NOT be able to submit a new query while an existing query is in progress.
5858
if (
5959
store.searchUiState !== SEARCH_UI_STATE.DEFAULT &&
60-
store.searchUiState !== SEARCH_UI_STATE.DONE
60+
store.searchUiState !== SEARCH_UI_STATE.DONE &&
61+
store.searchUiState !== SEARCH_UI_STATE.FAILED
62+
6163
) {
6264
console.error("Cannot submit query while existing query is in progress.");
6365

components/webui/client/src/pages/SearchPage/SearchQueryStatus/Results.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ const Results = () => {
4646
case SEARCH_UI_STATE.DONE:
4747
textType = "success";
4848
break;
49+
case SEARCH_UI_STATE.FAILED:
50+
textType = "danger";
51+
break;
4952
default:
5053
textType = "secondary";
5154
}

components/webui/client/src/pages/SearchPage/SearchState/typings.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ enum SEARCH_UI_STATE {
2121
* When the query is complete or cancelled.
2222
*/
2323
DONE,
24+
25+
/**
26+
* When the query failed due to an error.
27+
*/
28+
FAILED,
2429
}
2530

2631
export {SEARCH_UI_STATE};

components/webui/client/src/pages/SearchPage/SearchState/useUpdateStateWithMetadata.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import {useEffect} from "react";
22

3-
import {SEARCH_SIGNAL} from "@common/index.js";
3+
import {
4+
PRESTO_SEARCH_SIGNAL,
5+
SEARCH_SIGNAL,
6+
} from "@common/index.js";
7+
import {notification} from "antd";
48

59
import useSearchStore from "./index";
610
import {SEARCH_UI_STATE} from "./typings";
@@ -9,19 +13,30 @@ import {useResultsMetadata} from "./useResultsMetadata";
913

1014
/**
1115
* Custom hook to update the UI state to `DONE` when the results metadata signal indicates
12-
* that the query is complete.
16+
* that the query is complete, or `FAILED` if the query fails. If there is an error, it will
17+
* also display a notification with the error message.
1318
*/
1419
const useUiUpdateOnDoneSignal = () => {
1520
const {updateSearchUiState} = useSearchStore();
1621
const resultsMetadata = useResultsMetadata();
1722
useEffect(() => {
18-
if (null === resultsMetadata
19-
) {
23+
if (null === resultsMetadata) {
2024
return;
2125
}
2226

2327
if (resultsMetadata.lastSignal === SEARCH_SIGNAL.RESP_DONE) {
2428
updateSearchUiState(SEARCH_UI_STATE.DONE);
29+
} else if (resultsMetadata.lastSignal === PRESTO_SEARCH_SIGNAL.FAILED) {
30+
updateSearchUiState(SEARCH_UI_STATE.FAILED);
31+
notification.error({
32+
description: resultsMetadata.errorMsg || "An error occurred during search",
33+
duration: 15,
34+
key: `search-failed-${resultsMetadata._id}`,
35+
message: resultsMetadata.errorName || "Search Failed",
36+
pauseOnHover: true,
37+
placement: "bottomRight",
38+
showProgress: true,
39+
});
2540
}
2641
}, [
2742
resultsMetadata,

components/webui/common/index.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,20 @@ enum SEARCH_SIGNAL {
9090

9191
/**
9292
* Presto search-related signals.
93-
*
94-
* Note: Using type instead of enum to match `presto-client-node` type definition.
9593
*/
96-
type PRESTO_SEARCH_SIGNAL =
97-
| "WAITING_FOR_PREREQUISITES"
98-
| "QUEUED"
99-
| "WAITING_FOR_RESOURCES"
100-
| "DISPATCHING"
101-
| "PLANNING"
102-
| "STARTING"
103-
| "RUNNING"
104-
| "FINISHING"
105-
| "FINISHED"
106-
| "CANCELED"
107-
| "FAILED";
94+
enum PRESTO_SEARCH_SIGNAL {
95+
WAITING_FOR_PREREQUISITES = "WAITING_FOR_PREREQUISITES",
96+
QUEUED = "QUEUED",
97+
WAITING_FOR_RESOURCES = "WAITING_FOR_RESOURCES",
98+
DISPATCHING = "DISPATCHING",
99+
PLANNING = "PLANNING",
100+
STARTING = "STARTING",
101+
RUNNING = "RUNNING",
102+
FINISHING = "FINISHING",
103+
FINISHED = "FINISHED",
104+
CANCELED = "CANCELED",
105+
FAILED = "FAILED",
106+
}
108107

109108
/**
110109
* CLP query engines.
@@ -125,16 +124,17 @@ interface SearchResultsMetadataDocument {
125124
// eslint-disable-next-line no-warning-comments
126125
// TODO: Replace with Nullable<string> when the `@common` directory refactoring is completed.
127126
errorMsg: string | null;
127+
errorName: string | null;
128128
lastSignal: SEARCH_SIGNAL | PRESTO_SEARCH_SIGNAL;
129129
numTotalResults?: number;
130130
queryEngine: CLP_QUERY_ENGINES;
131131
}
132132
export {
133133
CLP_QUERY_ENGINES,
134+
PRESTO_SEARCH_SIGNAL,
134135
SEARCH_SIGNAL,
135136
};
136137
export type {
137-
PRESTO_SEARCH_SIGNAL,
138138
SearchResultsMetadataDocument,
139139
ClientToServerEvents,
140140
Err,

components/webui/server/src/routes/api/presto-search/index.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {StatusCodes} from "http-status-codes";
66

77
import {
88
CLP_QUERY_ENGINES,
9+
PRESTO_SEARCH_SIGNAL,
910
type SearchResultsMetadataDocument,
1011
} from "../../../../../common/index.js";
1112
import settings from "../../../../settings.json" with {type: "json"};
@@ -104,10 +105,30 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
104105
if (false === isResolved) {
105106
isResolved = true;
106107
reject(new Error("Presto search failed"));
108+
} else {
109+
searchResultsMetadataCollection.updateOne(
110+
{_id: searchJobId},
111+
{
112+
$set: {
113+
errorMsg: error.message,
114+
errorName: ("errorName" in error) ?
115+
error.errorName :
116+
null,
117+
lastSignal: PRESTO_SEARCH_SIGNAL.FAILED,
118+
},
119+
}
120+
).catch((err: unknown) => {
121+
request.log.error(
122+
err,
123+
"Failed to update Presto error metadata"
124+
);
125+
});
107126
}
108127
},
109128
query: queryString,
110129
state: (_, queryId, stats) => {
130+
// Type cast `presto-client` string literal type to our enum type.
131+
const newState = stats.state as PRESTO_SEARCH_SIGNAL;
111132
request.log.info({
112133
searchJobId: queryId,
113134
state: stats.state,
@@ -117,8 +138,9 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
117138
if (false === isResolved) {
118139
searchResultsMetadataCollection.insertOne({
119140
_id: queryId,
120-
lastSignal: stats.state,
121141
errorMsg: null,
142+
errorName: null,
143+
lastSignal: newState,
122144
queryEngine: CLP_QUERY_ENGINES.PRESTO,
123145
}).catch((err: unknown) => {
124146
request.log.error(err, "Failed to insert Presto metadata");
@@ -129,7 +151,7 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
129151
// Update metadata on subsequent calls
130152
searchResultsMetadataCollection.updateOne(
131153
{_id: queryId},
132-
{$set: {lastSignal: stats.state}}
154+
{$set: {lastSignal: newState}}
133155
).catch((err: unknown) => {
134156
request.log.error(err, "Failed to update Presto metadata");
135157
});

components/webui/server/src/routes/api/search/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,9 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
113113

114114
await searchResultsMetadataCollection.insertOne({
115115
_id: searchJobId.toString(),
116-
lastSignal: SEARCH_SIGNAL.RESP_QUERYING,
117116
errorMsg: null,
117+
errorName: null,
118+
lastSignal: SEARCH_SIGNAL.RESP_QUERYING,
118119
queryEngine: queryEngine,
119120
});
120121

@@ -207,8 +208,8 @@ const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
207208
},
208209
{
209210
$set: {
210-
lastSignal: SEARCH_SIGNAL.RESP_DONE,
211211
errorMsg: "Query cancelled before it could be completed.",
212+
lastSignal: SEARCH_SIGNAL.RESP_DONE,
212213
},
213214
}
214215
);

0 commit comments

Comments
 (0)