Skip to content

Commit

Permalink
Render current system status and transitioning blueprint (#484)
Browse files Browse the repository at this point in the history
* Return next blueprint and current status

* Display next provisioning

* Display added tables
  • Loading branch information
geoffxy authored Mar 30, 2024
1 parent 1c6c8d6 commit 092370d
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 7 deletions.
3 changes: 3 additions & 0 deletions src/brad/planner/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,6 @@ async def _notify_new_blueprint(
for callback in self._callbacks:
tasks.append(asyncio.create_task(callback(blueprint, score, trigger)))
await asyncio.gather(*tasks)

def replan_in_progress(self) -> bool:
return self._replan_in_progress
26 changes: 25 additions & 1 deletion src/brad/ui/manager_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from brad.blueprint import Blueprint
from brad.blueprint.table import Table
from brad.blueprint.manager import BlueprintManager
from brad.planner.abstract import BlueprintPlanner
from brad.config.engine import Engine
from brad.config.file import ConfigFile
from brad.daemon.monitor import Monitor
Expand All @@ -24,6 +25,7 @@
DisplayableVirtualEngine,
VirtualInfrastructure,
DisplayableTable,
Status,
)
from brad.daemon.front_end_metrics import FrontEndMetric
from brad.daemon.system_event_logger import SystemEventLogger, SystemEventRecord
Expand All @@ -43,6 +45,7 @@ def __init__(
self.monitor = monitor
self.blueprint_mgr = blueprint_mgr
self.system_event_logger = system_event_logger
self.planner: Optional[BlueprintPlanner] = None

async def serve_forever(self) -> None:
global manager # pylint: disable=global-statement
Expand Down Expand Up @@ -169,7 +172,20 @@ def get_system_state(filter_tables_for_demo: bool = False) -> SystemState:
if t.name in txn_tables:
t.is_writer = True
virtual_infra = VirtualInfrastructure(engines=[vdbe1, vdbe2])
system_state = SystemState(virtual_infra=virtual_infra, blueprint=dbp)

status = _determine_current_status(manager)
if status is Status.Transitioning:
next_blueprint = manager.blueprint_mgr.get_transition_metadata().next_blueprint
assert next_blueprint is not None
next_dbp = DisplayableBlueprint.from_blueprint(next_blueprint)
else:
next_dbp = None
system_state = SystemState(
status=status,
virtual_infra=virtual_infra,
blueprint=dbp,
next_blueprint=next_dbp,
)
_add_reverse_mapping_temp(system_state)
return system_state

Expand Down Expand Up @@ -222,6 +238,14 @@ def _add_reverse_mapping_temp(system_state: SystemState) -> None:
table.mapped_to.append(veng_name)


def _determine_current_status(manager_impl: UiManagerImpl) -> Status:
if manager_impl.planner is not None and manager_impl.planner.replan_in_progress():
return Status.Planning
if manager_impl.blueprint_mgr.get_transition_metadata().next_blueprint is not None:
return Status.Transitioning
return Status.Running


@app.get("/api/1/system_events")
def get_system_events() -> List[SystemEventRecord]:
assert manager is not None
Expand Down
9 changes: 9 additions & 0 deletions src/brad/ui/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import enum
from typing import List, Dict, Optional
from pydantic import BaseModel, AwareDatetime

Expand Down Expand Up @@ -95,6 +96,14 @@ class VirtualInfrastructure(BaseModel):
engines: List[DisplayableVirtualEngine]


class Status(enum.Enum):
Running = "running"
Planning = "planning"
Transitioning = "transitioning"


class SystemState(BaseModel):
status: Status
virtual_infra: VirtualInfrastructure
blueprint: DisplayableBlueprint
next_blueprint: Optional[DisplayableBlueprint]
5 changes: 4 additions & 1 deletion ui/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ const REFRESH_INTERVAL_MS = 30 * 1000;

function App() {
const [systemState, setSystemState] = useState({
status: "running",
blueprint: null,
virtual_infra: null,
next_blueprint: null,
});
const [highlight, setHighlight] = useState({
hoverEngine: null,
Expand Down Expand Up @@ -115,7 +117,7 @@ function App() {

return (
<>
<Header />
<Header status={systemState.status} />
<div class="body-container">
<div class="column" style={{ flexGrow: 3 }}>
<h2 class="col-h2">Data Infrastructure</h2>
Expand All @@ -129,6 +131,7 @@ function App() {
/>
<BlueprintView
blueprint={systemState.blueprint}
nextBlueprint={systemState.next_blueprint}
highlight={highlight}
onTableHoverEnter={onTableHoverEnter}
onTableHoverExit={onTableHoverExit}
Expand Down
12 changes: 12 additions & 0 deletions ui/src/components/BlueprintView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@ import Panel from "./Panel";
import PhysDbView from "./PhysDbView";
import "./styles/BlueprintView.css";

function findNextEngine(engineName, nextBlueprint) {
if (nextBlueprint == null) return null;
for (const engine of nextBlueprint.engines) {
if (engine.name === engineName) {
return engine;
}
}
return null;
}

function BlueprintView({
blueprint,
nextBlueprint,
highlight,
onTableHoverEnter,
onTableHoverExit,
Expand All @@ -21,6 +32,7 @@ function BlueprintView({
highlight={highlight}
onTableHoverEnter={onTableHoverEnter}
onTableHoverExit={onTableHoverExit}
nextEngine={findNextEngine(name, nextBlueprint)}
/>
))}
</div>
Expand Down
20 changes: 15 additions & 5 deletions ui/src/components/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import "./styles/Header.css";
import bradLogo from "../assets/brad_logo.png";

function statusToDisplay(status) {
if (status === "transitioning") {
return "Transitioning...";
} else if (status === "planning") {
return "Running planner...";
} else {
return "Running";
}
}

function StatusText({ status, schema }) {
if (!!schema) {
return (
<div class="header-status-text">
{status} ({schema})
{statusToDisplay(status)} ({schema})
</div>
);
} else {
return <div class="header-status-text">{status}</div>;
return <div class="header-status-text">{statusToDisplay(status)}</div>;
}
}

function StatusIndicator({ status, schema }) {
return (
<div class="header-status">
<div class="header-status-icon"></div>
<div class={`header-status-icon ${status}`}></div>
<StatusText status={status} schema={schema} />
</div>
);
}

function Header() {
function Header({ status }) {
return (
<div class="header">
<div class="header-inner">
Expand All @@ -34,7 +44,7 @@ function Header() {
<strong>BRAD</strong> Dashboard
</div>
</div>
<StatusIndicator status="Running" schema="imdb_extended_100g" />
<StatusIndicator status={status} schema="imdb_extended_100g" />
</div>
</div>
);
Expand Down
33 changes: 33 additions & 0 deletions ui/src/components/PhysDbView.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,45 @@ import {
sortTablesToHoist,
} from "../highlight";

function addedTables(tables, nextEngine) {
if (nextEngine == null) return [];
const added = [];
const currTableSet = new Set();
for (const currTable of tables) {
currTableSet.add(currTable.name);
}
for (const table of nextEngine.tables) {
if (currTableSet.has(table.name)) continue;
added.push(table);
}
return added;
}

function PhysDbView({
name,
provisioning,
tables,
highlight,
onTableHoverEnter,
onTableHoverExit,
nextEngine,
}) {
const physDbName = name;
const sortedTables = sortTablesToHoist(highlight, physDbName, false, tables);
const addedTablesList = addedTables(tables, nextEngine);

return (
<div
class={`physdb-view ${highlightEngineViewClass(highlight, physDbName, false)}`}
>
<DbCylinder color="blue">{name}</DbCylinder>
<div class="physdb-view-prov">{provisioning}</div>
{nextEngine && (
<div class="physdb-view-prov transition">
{nextEngine.provisioning ? "→ " : ""}
{nextEngine.provisioning}
</div>
)}
<div class="db-table-set">
{sortedTables.map(({ name, is_writer, mapped_to }) => (
<TableView
Expand All @@ -43,6 +65,17 @@ function PhysDbView({
onTableHoverExit={onTableHoverExit}
/>
))}
{addedTablesList.map(({ name, is_writer }) => (
<TableView
key={name}
name={name}
isWriter={is_writer}
color="blue"
highlightClass="dim"
onTableHoverEnter={() => {}}
onTableHoverExit={() => {}}
/>
))}
</div>
</div>
);
Expand Down
13 changes: 13 additions & 0 deletions ui/src/components/styles/Header.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@
height: 12px;
border-radius: 50%;
margin: -2px 15px 0 0;
}

.header-status-icon.running {
background-color: #51a965;
box-shadow: 0 0 5px #51a965;
}

.header-status-icon.transitioning {
background-color: #ec8405;
box-shadow: 0 0 5px #ec8405;
}

.header-status-icon.planning {
background-color: #517aa9;
box-shadow: 0 0 5px #517aa9;
}
4 changes: 4 additions & 0 deletions ui/src/components/styles/PhysDbView.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
height: 30px;
}

.physdb-view-prov.transition {
color: #888;
}

.physdb-view.dim .db-cylinder,
.physdb-view.dim .physdb-view-prov {
opacity: 0.3;
Expand Down

0 comments on commit 092370d

Please sign in to comment.