Skip to content

Commit def9801

Browse files
authored
1 parent d425c8a commit def9801

File tree

5 files changed

+117
-6
lines changed

5 files changed

+117
-6
lines changed

packages/databricks-sdk-js/src/services/WorkflowRun.integ.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,61 @@ describe(__filename, function () {
101101
await workspaceService.delete({path: jobPath});
102102
}
103103
});
104+
105+
it("should run a broken notebook job", async () => {
106+
const cluster = await Cluster.fromClusterId(
107+
integSetup.client,
108+
integSetup.cluster.id
109+
);
110+
111+
const jobPath = `/tmp/sdk-js-integ-${integSetup.testRunId}.py`;
112+
const workspaceService = new WorkspaceService(integSetup.client);
113+
114+
await workspaceService.mkdirs({path: "/tmp"});
115+
116+
await workspaceService.import({
117+
path: jobPath,
118+
format: "SOURCE",
119+
language: "PYTHON",
120+
content: Buffer.from(
121+
`# Databricks notebook source
122+
# COMMAND ----------
123+
124+
pr int("Cell 1")
125+
126+
# COMMAND ----------
127+
128+
print("Cell 2")`
129+
).toString("base64"),
130+
overwrite: true,
131+
});
132+
133+
try {
134+
const progress: Array<WorkflowRun> = [];
135+
const output = await cluster.runNotebookAndWait({
136+
path: `${jobPath}`,
137+
onProgress: (
138+
_state: jobs.RunLifeCycleState,
139+
run: WorkflowRun
140+
) => {
141+
progress.push(run);
142+
},
143+
});
144+
145+
assert(progress.length > 1);
146+
assert.equal(
147+
progress[progress.length - 1].lifeCycleState,
148+
"INTERNAL_ERROR"
149+
);
150+
151+
assert(
152+
output.views &&
153+
output.views.length > 0 &&
154+
output.views[0].content
155+
);
156+
assert(output.views[0].content.startsWith("<!DOCTYPE html>"));
157+
} finally {
158+
await workspaceService.delete({path: jobPath});
159+
}
160+
});
104161
});

packages/databricks-sdk-js/src/services/WorkflowRun.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ export class WorkflowRun {
6262

6363
async export(task?: RunTask): Promise<ExportRunOutput> {
6464
task = task || this.tasks![0];
65-
if (this.lifeCycleState !== "TERMINATED") {
65+
if (
66+
this.lifeCycleState !== "TERMINATED" &&
67+
this.lifeCycleState !== "INTERNAL_ERROR"
68+
) {
6669
throw new Error("Run is not terminated");
6770
}
6871
if (!this.tasks || !this.tasks.length) {

packages/databricks-vscode/src/run/WorkflowOutputPanel.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,30 @@ export class WorkflowOutputPanel {
6464
});
6565
}
6666

67+
private getStateString(runState: jobs.RunLifeCycleState): string {
68+
switch (runState) {
69+
case "PENDING":
70+
return "Pending";
71+
case "RUNNING":
72+
return "Running";
73+
case "TERMINATED":
74+
return "Terminated";
75+
case "SKIPPED":
76+
return "Skipped";
77+
case "INTERNAL_ERROR":
78+
return "Failed";
79+
default:
80+
return "Unknown";
81+
}
82+
}
83+
6784
async updateState(
6885
cluster: Cluster,
69-
state: jobs.RunLifeCycleState,
86+
runState: jobs.RunLifeCycleState,
7087
run: WorkflowRun
7188
) {
89+
const state = this.getStateString(runState);
90+
7291
this.panel.webview.postMessage({
7392
type: "status",
7493
state,

packages/databricks-vscode/src/run/WorkflowRunner.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {WorkflowOutputPanel} from "./WorkflowOutputPanel";
2222

2323
export class WorkflowRunner implements Disposable {
2424
private panels = new Map<string, WorkflowOutputPanel>();
25+
private disposables = new Array<Disposable>();
2526

2627
constructor(
2728
private context: ExtensionContext,
@@ -32,6 +33,7 @@ export class WorkflowRunner implements Disposable {
3233
for (const panel of this.panels.values()) {
3334
panel.dispose();
3435
}
36+
this.disposables.forEach((d) => d.dispose());
3537
}
3638

3739
private async getPanelForUri(uri: Uri) {
@@ -54,6 +56,9 @@ export class WorkflowRunner implements Disposable {
5456
),
5557
this.context.extensionUri
5658
);
59+
this.disposables.push(
60+
panel.onDidDispose(() => this.panels.delete(key))
61+
);
5762
this.panels.set(key, panel);
5863
}
5964

packages/databricks-vscode/webview-ui/job.html

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,13 @@
9393
display: none;
9494
}
9595

96+
.alert-error .error-icon {
97+
display: inline-block;
98+
padding: 0 8px;
99+
}
100+
96101
.alert-error {
102+
display: flex;
97103
padding: 8px;
98104
margin: 8px;
99105
color: rgb(200, 45, 76);
@@ -117,7 +123,7 @@
117123
}
118124

119125
.output.error #error {
120-
display: block;
126+
display: flex;
121127
}
122128

123129
.details {
@@ -139,8 +145,29 @@
139145
<iframe id="frame"></iframe>
140146
<pre id="stdout"></pre>
141147
<div class="alert-error" id="error">
142-
<b id="error-description"></b>
143-
<pre id="error-stack"></pre>
148+
<span class="error-icon">
149+
<svg
150+
width="1em"
151+
height="1em"
152+
viewBox="0 0 24 24"
153+
fill="none"
154+
xmlns="http://www.w3.org/2000/svg"
155+
aria-hidden="true"
156+
focusable="false"
157+
class=""
158+
>
159+
<path
160+
fill-rule="evenodd"
161+
clip-rule="evenodd"
162+
d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 11c-.55 0-1-.45-1-1V8c0-.55.45-1 1-1s1 .45 1 1v4c0 .55-.45 1-1 1zm-1 2v2h2v-2h-2z"
163+
fill="currentColor"
164+
></path>
165+
</svg>
166+
</span>
167+
<div>
168+
<b id="error-description"></b>
169+
<pre id="error-stack"></pre>
170+
</div>
144171
</div>
145172
</div>
146173
<div class="details">
@@ -174,7 +201,7 @@
174201
</li>
175202
<li>
176203
<span class="label">Status:</span>
177-
<span class="value" id="run-status">SYNCING</span>
204+
<span class="value" id="run-status">Synchronizing</span>
178205
</li>
179206
</ul>
180207
</div>

0 commit comments

Comments
 (0)