mirror of
https://github.com/wassname/ray.git
synced 2026-06-29 18:27:03 +08:00
[Dashboard] Update ActorState in dashboard to support new actor states (#9855)
* Update ActorState in dashboard to support new actor states * Update dashboard documentation for new states * Add missing state to doc Co-authored-by: Max Fitton <max@semprehealth.com>
This commit is contained in:
@@ -146,52 +146,66 @@ export type RayletWorkerStats = {
|
||||
coreWorkerStats: RayletCoreWorkerStats;
|
||||
};
|
||||
|
||||
export type RayletActorInfo =
|
||||
| {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
averageTaskExecutionSpeed: number;
|
||||
children: RayletInfoResponse["actors"];
|
||||
// currentTaskFuncDesc: string[];
|
||||
ipAddress: string;
|
||||
jobId: string;
|
||||
nodeId: string;
|
||||
numExecutedTasks: number;
|
||||
numLocalObjects: number;
|
||||
numObjectRefsInScope: number;
|
||||
pid: number;
|
||||
port: number;
|
||||
state:
|
||||
| ActorState.Creating
|
||||
| ActorState.Alive
|
||||
| ActorState.Restarting
|
||||
| ActorState.Dead;
|
||||
taskQueueLength: number;
|
||||
timestamp: number;
|
||||
usedObjectStoreMemory: number;
|
||||
usedResources: { [key: string]: ResourceAllocations };
|
||||
currentTaskDesc?: string;
|
||||
numPendingTasks?: number;
|
||||
webuiDisplay?: Record<string, string>;
|
||||
}
|
||||
| {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
requiredResources: { [key: string]: number };
|
||||
state: ActorState.Invalid;
|
||||
invalidStateType?: InvalidStateType;
|
||||
};
|
||||
|
||||
export type InvalidStateType = "infeasibleActor" | "pendingActor";
|
||||
|
||||
export enum ActorState {
|
||||
Invalid = -1,
|
||||
Creating = 0,
|
||||
Alive = 1,
|
||||
Restarting = 2,
|
||||
Dead = 3,
|
||||
DependenciesUnready = 0,
|
||||
PendingCreation = 1,
|
||||
Alive = 2,
|
||||
Restarting = 3,
|
||||
Dead = 4,
|
||||
}
|
||||
|
||||
export type RayletActorInfo = FullActorInfo | PartialActorInfo;
|
||||
|
||||
export type FullActorInfo = {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
averageTaskExecutionSpeed: number;
|
||||
children: RayletInfoResponse["actors"];
|
||||
// currentTaskFuncDesc: string[];
|
||||
ipAddress: string;
|
||||
jobId: string;
|
||||
nodeId: string;
|
||||
numExecutedTasks: number;
|
||||
numLocalObjects: number;
|
||||
numObjectRefsInScope: number;
|
||||
pid: number;
|
||||
port: number;
|
||||
state:
|
||||
| ActorState.Alive
|
||||
| ActorState.Restarting
|
||||
| ActorState.Dead
|
||||
| ActorState.DependenciesUnready
|
||||
| ActorState.PendingCreation;
|
||||
taskQueueLength: number;
|
||||
timestamp: number;
|
||||
usedObjectStoreMemory: number;
|
||||
usedResources: { [key: string]: ResourceAllocations };
|
||||
currentTaskDesc?: string;
|
||||
numPendingTasks?: number;
|
||||
webuiDisplay?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type PartialActorInfo = {
|
||||
actorId: string;
|
||||
actorTitle: string;
|
||||
requiredResources: { [key: string]: number };
|
||||
state: ActorState.Invalid;
|
||||
invalidStateType?: InvalidStateType;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line
|
||||
export function isFullActorInfo(
|
||||
rayletInfo: RayletActorInfo,
|
||||
): rayletInfo is FullActorInfo {
|
||||
// Lint disabled because arrow functions don't play well with type guards.
|
||||
// This function is used to determine what kind of information we have about
|
||||
// a given actor in a response based on its state.
|
||||
return rayletInfo.state !== ActorState.Invalid;
|
||||
}
|
||||
|
||||
export type InvalidStateType = "infeasibleActor" | "pendingActor";
|
||||
|
||||
export type RayletInfoResponse = {
|
||||
nodes: {
|
||||
[ip: string]: {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
checkProfilingStatus,
|
||||
CheckProfilingStatusResponse,
|
||||
getProfilingResultURL,
|
||||
isFullActorInfo,
|
||||
launchKillActor,
|
||||
launchProfiling,
|
||||
RayletActorInfo,
|
||||
@@ -84,7 +85,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
|
||||
handleProfilingClick = (duration: number) => async () => {
|
||||
const actor = this.props.actor;
|
||||
if (actor.state !== ActorState.Invalid) {
|
||||
if (actor.state === ActorState.Alive) {
|
||||
const profilingId = await launchProfiling(
|
||||
actor.nodeId,
|
||||
actor.pid,
|
||||
@@ -117,10 +118,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
|
||||
killActor = () => {
|
||||
const actor = this.props.actor;
|
||||
if (
|
||||
actor.state === ActorState.Creating ||
|
||||
actor.state === ActorState.Alive
|
||||
) {
|
||||
if (actor.state === ActorState.Alive) {
|
||||
launchKillActor(actor.actorId, actor.ipAddress, actor.port);
|
||||
}
|
||||
};
|
||||
@@ -128,83 +126,84 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
render() {
|
||||
const { classes, actor } = this.props;
|
||||
const { expanded, profiling } = this.state;
|
||||
|
||||
const information =
|
||||
actor.state !== ActorState.Invalid
|
||||
? [
|
||||
{
|
||||
label: "Resources",
|
||||
value:
|
||||
Object.entries(actor.usedResources).length > 0 &&
|
||||
Object.entries(actor.usedResources)
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${sum(
|
||||
value.resourceSlots.map((slot) => slot.allocation),
|
||||
)} ${key}`,
|
||||
)
|
||||
.join(", "),
|
||||
},
|
||||
{
|
||||
label: "Number of pending tasks",
|
||||
value: actor.taskQueueLength.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of tasks that are currently pending to execute on this actor. If this number " +
|
||||
"remains consistently high, it may indicate that this actor is a bottleneck in your application.",
|
||||
},
|
||||
{
|
||||
label: "Number of executed tasks",
|
||||
value: actor.numExecutedTasks.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of tasks this actor has executed throughout its lifetimes.",
|
||||
},
|
||||
{
|
||||
label: "Number of ObjectRefs in scope",
|
||||
value: actor.numObjectRefsInScope.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of ObjectRefs that this actor is keeping in scope via its internal state. " +
|
||||
"This does not imply that the objects are in active use or colocated on the node with the actor " +
|
||||
`currently. This can be useful for debugging memory leaks. See the docs at ${memoryDebuggingDocLink} ` +
|
||||
"for more information.",
|
||||
},
|
||||
{
|
||||
label: "Number of local objects",
|
||||
value: actor.numLocalObjects.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of small objects that this actor has stored in its local in-process memory store. This can be useful for " +
|
||||
`debugging memory leaks. See the docs at ${memoryDebuggingDocLink} for more information`,
|
||||
},
|
||||
{
|
||||
label: "Object store memory used (MiB)",
|
||||
value: actor.usedObjectStoreMemory.toLocaleString(),
|
||||
tooltip:
|
||||
"The total amount of memory that this actor is occupying in the Ray object store. " +
|
||||
"If this number is increasing without bounds, you might have a memory leak. See " +
|
||||
`the docs at: ${memoryDebuggingDocLink} for more information.`,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: "Actor ID",
|
||||
value: actor.actorId,
|
||||
tooltip: "",
|
||||
},
|
||||
{
|
||||
label: "Required resources",
|
||||
value:
|
||||
Object.entries(actor.requiredResources).length > 0 &&
|
||||
Object.entries(actor.requiredResources)
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([key, value]) => `${value.toLocaleString()} ${key}`)
|
||||
.join(", "),
|
||||
tooltip: "",
|
||||
},
|
||||
];
|
||||
const invalidStateType = isFullActorInfo(actor)
|
||||
? undefined
|
||||
: actor.invalidStateType;
|
||||
const information = isFullActorInfo(actor)
|
||||
? [
|
||||
{
|
||||
label: "Resources",
|
||||
value:
|
||||
Object.entries(actor.usedResources).length > 0 &&
|
||||
Object.entries(actor.usedResources)
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${sum(
|
||||
value.resourceSlots.map((slot) => slot.allocation),
|
||||
)} ${key}`,
|
||||
)
|
||||
.join(", "),
|
||||
},
|
||||
{
|
||||
label: "Number of pending tasks",
|
||||
value: actor.taskQueueLength.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of tasks that are currently pending to execute on this actor. If this number " +
|
||||
"remains consistently high, it may indicate that this actor is a bottleneck in your application.",
|
||||
},
|
||||
{
|
||||
label: "Number of executed tasks",
|
||||
value: actor.numExecutedTasks.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of tasks this actor has executed throughout its lifetimes.",
|
||||
},
|
||||
{
|
||||
label: "Number of ObjectRefs in scope",
|
||||
value: actor.numObjectRefsInScope.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of ObjectRefs that this actor is keeping in scope via its internal state. " +
|
||||
"This does not imply that the objects are in active use or colocated on the node with the actor " +
|
||||
`currently. This can be useful for debugging memory leaks. See the docs at ${memoryDebuggingDocLink} ` +
|
||||
"for more information.",
|
||||
},
|
||||
{
|
||||
label: "Number of local objects",
|
||||
value: actor.numLocalObjects.toLocaleString(),
|
||||
tooltip:
|
||||
"The number of small objects that this actor has stored in its local in-process memory store. This can be useful for " +
|
||||
`debugging memory leaks. See the docs at ${memoryDebuggingDocLink} for more information`,
|
||||
},
|
||||
{
|
||||
label: "Object store memory used (MiB)",
|
||||
value: actor.usedObjectStoreMemory.toLocaleString(),
|
||||
tooltip:
|
||||
"The total amount of memory that this actor is occupying in the Ray object store. " +
|
||||
"If this number is increasing without bounds, you might have a memory leak. See " +
|
||||
`the docs at: ${memoryDebuggingDocLink} for more information.`,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
label: "Actor ID",
|
||||
value: actor.actorId,
|
||||
tooltip: "",
|
||||
},
|
||||
{
|
||||
label: "Required resources",
|
||||
value:
|
||||
Object.entries(actor.requiredResources).length > 0 &&
|
||||
Object.entries(actor.requiredResources)
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([key, value]) => `${value.toLocaleString()} ${key}`)
|
||||
.join(", "),
|
||||
tooltip: "",
|
||||
},
|
||||
];
|
||||
|
||||
// Construct the custom message from the actor.
|
||||
let actorCustomDisplay: JSX.Element[] = [];
|
||||
if (actor.state !== ActorState.Invalid && actor.webuiDisplay) {
|
||||
if (isFullActorInfo(actor) && actor.webuiDisplay) {
|
||||
actorCustomDisplay = Object.keys(actor.webuiDisplay)
|
||||
.sort()
|
||||
.map((key, _, __) => {
|
||||
@@ -241,7 +240,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Typography className={classes.title}>
|
||||
{actor.state !== ActorState.Invalid ? (
|
||||
{isFullActorInfo(actor) ? (
|
||||
<React.Fragment>
|
||||
Actor {actor.actorId}{" "}
|
||||
{Object.entries(actor.children).length > 0 && (
|
||||
@@ -269,7 +268,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
</React.Fragment>
|
||||
))}
|
||||
){" "}
|
||||
{actor.state === 0 && (
|
||||
{actor.state === ActorState.Alive && (
|
||||
<span className={classes.action} onClick={this.killActor}>
|
||||
Kill Actor
|
||||
</span>
|
||||
@@ -303,7 +302,7 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
) : actor.invalidStateType === "infeasibleActor" ? (
|
||||
<span className={classes.invalidStateTypeInfeasible}>
|
||||
{actor.actorTitle} cannot be created because the Ray cluster
|
||||
cannot satisfy its resource requirements.)
|
||||
cannot satisfy its resource requirements.
|
||||
</span>
|
||||
) : (
|
||||
<span className={classes.invalidStateTypePendingActor}>
|
||||
@@ -315,8 +314,9 @@ class Actor extends React.Component<Props & WithStyles<typeof styles>, State> {
|
||||
actorDetails={information}
|
||||
actorTitle={actor.actorTitle}
|
||||
actorState={actor.state}
|
||||
invalidStateType={invalidStateType}
|
||||
/>
|
||||
{actor.state !== ActorState.Invalid && (
|
||||
{isFullActorInfo(actor) && (
|
||||
<React.Fragment>
|
||||
{actorCustomDisplay.length > 0 && (
|
||||
<React.Fragment>{actorCustomDisplay}</React.Fragment>
|
||||
|
||||
@@ -77,18 +77,28 @@ const actorStateReprStyles = makeStyles((theme: Theme) =>
|
||||
|
||||
const ActorStateRepr: React.FC<ActorStateReprProps> = ({ state, ist }) => {
|
||||
const classes = actorStateReprStyles();
|
||||
const { Alive, Dead, Creating, Restarting, Invalid } = ActorState;
|
||||
const {
|
||||
Alive,
|
||||
Dead,
|
||||
PendingCreation,
|
||||
Restarting,
|
||||
DependenciesUnready,
|
||||
Invalid,
|
||||
} = ActorState;
|
||||
switch (state) {
|
||||
case Invalid:
|
||||
console.log(ist);
|
||||
if (ist === "infeasibleActor") {
|
||||
return <div className={classes.infeasible}>Infeasible</div>;
|
||||
}
|
||||
if (ist === "pendingActor") {
|
||||
return <div className={classes.pending}>Pending Resources</div>;
|
||||
return <div className={classes.pending}>Pending</div>;
|
||||
}
|
||||
return <div className={classes.unknown}>Unknown</div>;
|
||||
case Creating:
|
||||
case PendingCreation:
|
||||
return <div className={classes.creating}>Creating</div>;
|
||||
case DependenciesUnready:
|
||||
return <div className={classes.creating}>Dependencies Unready</div>;
|
||||
case Alive:
|
||||
return <div className={classes.alive}>Alive</div>;
|
||||
case Restarting:
|
||||
|
||||
@@ -7,7 +7,11 @@ import {
|
||||
} from "@material-ui/core";
|
||||
import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { ActorState, RayletActorInfo, RayletInfoResponse } from "../../../api";
|
||||
import {
|
||||
isFullActorInfo,
|
||||
RayletActorInfo,
|
||||
RayletInfoResponse,
|
||||
} from "../../../api";
|
||||
import { filterObj } from "../../../common/util";
|
||||
import { StoreState } from "../../../store";
|
||||
import Actors from "./Actors";
|
||||
@@ -29,8 +33,7 @@ const actorMatchesSearch = (
|
||||
const getNestedActorTitles = (actor: RayletActorInfo): string[] => {
|
||||
const actorTitle = actor.actorTitle;
|
||||
const titles: string[] = actorTitle ? [actorTitle] : [];
|
||||
// state of -1 indicates an actor data record that does not have children.
|
||||
if (actor.state === ActorState.Invalid) {
|
||||
if (!isFullActorInfo(actor)) {
|
||||
return titles;
|
||||
}
|
||||
const children = actor["children"];
|
||||
|
||||
Reference in New Issue
Block a user