Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"dev": "deno run --watch main.ts"
},
"imports": {
"@std/assert": "jsr:@std/assert@^1.0.11",
"@std/assert": "jsr:@std/assert@1.0.11",
"cli-table3": "https://esm.sh/cli-table3@0.6.5",
"yaml": "https://esm.sh/yaml@2.6.1",
"semver": "https://esm.sh/semver@7.6.3",
Expand Down
42 changes: 13 additions & 29 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"@commander-js/extra-typings": "^12.1.0",
"@inkjs/ui": "^2.0.0",
"@inquirer/prompts": "^5.1.2",
"@sfcompute/nodes-sdk-alpha": "0.1.0-alpha.21",
"@sfcompute/nodes-sdk-alpha": "0.1.0-alpha.22",
"@types/ms": "^0.7.34",
"async-retry": "^1.3.3",
"axios": "^1.8.4",
Expand Down
34 changes: 23 additions & 11 deletions src/lib/nodes/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
roundStartDate,
selectTime,
} from "../../helpers/units.ts";
import { formatDate } from "../../helpers/format-date.ts";
import { GPUS_PER_NODE } from "../constants.ts";

dayjs.extend(utc);
Expand Down Expand Up @@ -253,9 +254,6 @@ async function createNodesAction(
if (isReserved) {
// Handle start time (options.start comes from parseStartDateOrNow parser)
const startDate = options.start;
if (typeof startDate !== "string") {
createParams.start_at = Math.floor(startDate.getTime() / 1000);
}

// Check if the start date is "NOW" or on an hour boundary
const startDateIsValid = startDate === "NOW" ||
Expand All @@ -276,27 +274,41 @@ async function createNodesAction(
: suggestedLowerStart.toDate();
}
}
createParams.start_at = Math.floor(
(options.start === "NOW"
? new Date().getTime()
: options.start.getTime()) /
1000,
);
// Pass undefined for "NOW" to avoid race conditions - the API will use current time
if (options.start !== "NOW") {
createParams.start_at = Math.floor(options.start.getTime() / 1000);
}

// Handle end time and/or duration
if (options.end || options.duration) {
let endDate = options.end;
const endStartTime = typeof options.start === "string"
? new Date()
: options.start;
if (!endDate) {
// Use the actual start time (current time if "NOW", or the specified start)
endDate = new Date(
new Date(createParams.start_at! * 1000).getTime() +
(options.duration! * 1000),
endStartTime.getTime() + (options.duration! * 1000),
);
}

const endDateIsValid = dayjs(endDate).isSame(
dayjs(endDate).startOf("hour"),
);
if (!endDateIsValid) {
// If the start time was valid, show the user the start time so they're no confused about
// which time they're selecting
if (startDateIsValid) {
ora(
`Using start time: ${
cyan(
`${formatDate(endStartTime, { forceIncludeTime: true })} ${
dayjs(endStartTime).format("z")
}`,
)
}`,
).info();
}
if (!options.yes) {
const selectedTime = await selectTime(endDate, {
message: `End time must be on an hour boundary. ${
Expand Down