mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-27 08:02:39 +00:00
fix: make the autoscaling Test scaling button run the integration (#11972)
* fix: make the autoscaling Test scaling button run the integration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: bump ee ref Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: bound the test scaling worker input at zero Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: update ee-repo-ref to a2a23aebcf91985778fb632a415a6990d022f7c8 This commit updates the EE repository reference after PR #917 was merged in windmill-ee-private. Previous ee-repo-ref: c9e8c8853e2042a11797e322e1e4bb4be241380c New ee-repo-ref: a2a23aebcf91985778fb632a415a6990d022f7c8 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
windmill-internal-app[bot]
parent
fb193d7a81
commit
72c6b10821
@@ -1 +1 @@
|
||||
5cfc0dc6760ea7f631fc98ea1edd39adfc55bf11
|
||||
a2a23aebcf91985778fb632a415a6990d022f7c8
|
||||
|
||||
@@ -35,6 +35,7 @@ pub fn global_service() -> Router {
|
||||
"/list_autoscaling_events/{worker_group}",
|
||||
get(list_autoscaling_events),
|
||||
)
|
||||
.route("/test_autoscaling/{worker_group}", post(test_autoscaling))
|
||||
.route(
|
||||
"/native_kubernetes_autoscaling_healthcheck",
|
||||
get(native_kubernetes_autoscaling_healthcheck),
|
||||
@@ -419,6 +420,48 @@ async fn native_kubernetes_autoscaling_healthcheck() -> Result<(), error::Error>
|
||||
))
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct TestAutoscalingResponse {
|
||||
job_id: Option<String>,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "enterprise", feature = "private"))]
|
||||
async fn test_autoscaling(
|
||||
authed: ApiAuthed,
|
||||
Extension(db): Extension<DB>,
|
||||
Path(worker_group): Path<String>,
|
||||
Json(test): Json<windmill_autoscaling::autoscaling_ee::TestAutoscaling>,
|
||||
) -> error::JsonResult<TestAutoscalingResponse> {
|
||||
require_devops_role(&db, &authed).await?;
|
||||
audit_log(
|
||||
&db,
|
||||
&authed,
|
||||
"worker_config.test_autoscaling",
|
||||
ActionKind::Execute,
|
||||
"global",
|
||||
Some(&worker_group),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let job_id = windmill_autoscaling::autoscaling_ee::test_autoscaling(
|
||||
&db,
|
||||
&worker_group,
|
||||
test,
|
||||
&authed.email,
|
||||
)
|
||||
.await?;
|
||||
Ok(Json(TestAutoscalingResponse {
|
||||
job_id: job_id.map(|id| id.to_string()),
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "enterprise", feature = "private")))]
|
||||
async fn test_autoscaling() -> error::JsonResult<TestAutoscalingResponse> {
|
||||
Err(error::Error::BadRequest(
|
||||
"Autoscaling available only in the enterprise version".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
async fn list_available_python_versions() -> error::JsonResult<Vec<String>> {
|
||||
#[cfg(not(all(feature = "python", feature = "run_inline")))]
|
||||
return Err(error::Error::BadRequest(
|
||||
|
||||
@@ -24649,6 +24649,56 @@ paths:
|
||||
items:
|
||||
$ref: "#/components/schemas/AutoscalingEvent"
|
||||
|
||||
/configs/test_autoscaling/{worker_group}:
|
||||
post:
|
||||
summary: Run an autoscaling integration once for a worker group, without recording an autoscaling event
|
||||
operationId: testAutoscaling
|
||||
tags:
|
||||
- config
|
||||
parameters:
|
||||
- name: worker_group
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
desired_workers:
|
||||
type: integer
|
||||
minimum: 0
|
||||
integration:
|
||||
description: The integration to run, as in the worker group's autoscaling config
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [script, kubernetes, dryrun]
|
||||
path:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
required:
|
||||
- desired_workers
|
||||
- integration
|
||||
responses:
|
||||
"200":
|
||||
description: The job queued for a script integration
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
job_id:
|
||||
type: string
|
||||
nullable: true
|
||||
|
||||
/configs/native_kubernetes_autoscaling_healthcheck:
|
||||
get:
|
||||
summary: Check Kubernetes autoscaling health for a worker group
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
import ScriptPicker from './ScriptPicker.svelte'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { untrack } from 'svelte'
|
||||
import ConfirmationModal from './common/confirmationModal/ConfirmationModal.svelte'
|
||||
import { createAsyncConfirmationModal } from './common/confirmationModal/asyncConfirmationModal.svelte'
|
||||
import Portal from './Portal.svelte'
|
||||
|
||||
interface Props {
|
||||
worker_group: string
|
||||
config: AutoscalingConfig | undefined
|
||||
worker_tags: string[] | undefined
|
||||
/** Whether the draft config gives the group any tags (worker_tags or dedicated workers). */
|
||||
@@ -29,6 +33,7 @@
|
||||
}
|
||||
|
||||
let {
|
||||
worker_group,
|
||||
config = $bindable(),
|
||||
worker_tags,
|
||||
group_has_tags,
|
||||
@@ -66,6 +71,54 @@
|
||||
}
|
||||
}
|
||||
|
||||
const confirmationModal = createAsyncConfirmationModal()
|
||||
|
||||
async function testScaling() {
|
||||
const integration = config?.integration
|
||||
if (!integration) return
|
||||
if (integration.type === 'script' && !integration['path']) {
|
||||
sendUserToast('Please select a script before testing scaling', true)
|
||||
return
|
||||
}
|
||||
const desired_workers = test_input
|
||||
let job_id: string | null | undefined
|
||||
let failed = false
|
||||
const confirmed = await confirmationModal.ask({
|
||||
title: `Scale ${worker_group} to ${desired_workers} workers?`,
|
||||
confirmationText: 'Scale now',
|
||||
type: 'reload',
|
||||
children:
|
||||
integration.type === 'kubernetes'
|
||||
? `This sets the worker group's replica count to ${desired_workers} now. If autoscaling is enabled, it adjusts the count again on its next pass.`
|
||||
: `This runs the integration script once with desired_workers set to ${desired_workers}, and it scales the group if the script does. If autoscaling is enabled, it adjusts the count again on its next pass.`,
|
||||
onConfirmed: async () => {
|
||||
try {
|
||||
job_id = (
|
||||
await ConfigService.testAutoscaling({
|
||||
workerGroup: worker_group,
|
||||
requestBody: { desired_workers, integration: $state.snapshot(integration) }
|
||||
})
|
||||
).job_id
|
||||
} catch (e: any) {
|
||||
failed = true
|
||||
sendUserToast('Test scaling failed', true, [], e?.body ?? e?.message)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (!confirmed || failed) return
|
||||
if (job_id) {
|
||||
const id = job_id
|
||||
sendUserToast('Autoscaling script queued in the admins workspace', false, [
|
||||
{
|
||||
label: 'See job',
|
||||
callback: () => window.open('/run/' + id + '?workspace=admins', '_blank')
|
||||
}
|
||||
])
|
||||
} else {
|
||||
sendUserToast(`Scaled ${worker_group} to ${desired_workers} workers`)
|
||||
}
|
||||
}
|
||||
|
||||
let noTagsToCount = $derived(!!config?.enabled && !group_has_tags && !config.custom_tags?.length)
|
||||
|
||||
let collapsed: boolean = $state(untrack(() => !noTagsToCount))
|
||||
@@ -266,22 +319,11 @@
|
||||
/>
|
||||
|
||||
<div class="flex flex-row gap-2 justify-end mt-4">
|
||||
<Button
|
||||
variant="default"
|
||||
unifiedSize="md"
|
||||
onclick={() => {
|
||||
if (!config?.integration?.['path']) {
|
||||
sendUserToast('Please select a script before testing scaling', true)
|
||||
return
|
||||
}
|
||||
if (!config?.integration?.['tag']) {
|
||||
sendUserToast('Please select a custom tag before testing scaling', true)
|
||||
return
|
||||
}
|
||||
}}>Test scaling</Button
|
||||
<Button variant="default" unifiedSize="md" {disabled} onclick={testScaling}
|
||||
>Test scaling</Button
|
||||
>
|
||||
<div class="flex text-xs flex-row gap-2 items-center">
|
||||
<input class="!w-16" type="number" bind:value={test_input} />
|
||||
<input class="!w-16" type="number" min="0" bind:value={test_input} />
|
||||
workers
|
||||
</div>
|
||||
</div>
|
||||
@@ -317,9 +359,11 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2 justify-end">
|
||||
<Button unifiedSize="md" variant="default">Test scaling</Button>
|
||||
<Button unifiedSize="md" variant="default" {disabled} onclick={testScaling}
|
||||
>Test scaling</Button
|
||||
>
|
||||
<div class="flex text-xs flex-row gap-2 items-center">
|
||||
<input class="!w-16" type="number" bind:value={test_input} />
|
||||
<input class="!w-16" type="number" min="0" bind:value={test_input} />
|
||||
workers
|
||||
</div>
|
||||
</div>
|
||||
@@ -547,3 +591,7 @@
|
||||
</Label>
|
||||
</Section>
|
||||
</Section>
|
||||
|
||||
<Portal>
|
||||
<ConfirmationModal {...confirmationModal.props} />
|
||||
</Portal>
|
||||
|
||||
@@ -1078,6 +1078,7 @@
|
||||
<div class="mt-8"></div>
|
||||
|
||||
<AutoscalingConfigEditor
|
||||
worker_group={name}
|
||||
worker_tags={config?.worker_tags}
|
||||
group_has_tags={nconfig.worker_tags !== undefined
|
||||
? nconfig.worker_tags.length > 0
|
||||
|
||||
Reference in New Issue
Block a user