Skip to content

Refactor FleetAutoscaler state from map to typed struct#4315

Merged
markmandel merged 2 commits intoagones-dev:mainfrom
markmandel:cleanup/fas-state
Oct 31, 2025
Merged

Refactor FleetAutoscaler state from map to typed struct#4315
markmandel merged 2 commits intoagones-dev:mainfrom
markmandel:cleanup/fas-state

Conversation

@markmandel
Copy link
Copy Markdown
Collaborator

What type of PR is this?

Uncomment only one /kind <> line, press enter to put that in a new line, and remove leading whitespace from that line:

/kind breaking
/kind bug

/kind cleanup

/kind documentation
/kind feature
/kind hotfix
/kind release

What this PR does / Why we need it:

Replace the generic map[string]any state in fasThread with a typed fasState struct containing a wasmPlugin field. This change:

  • Introduces fasState struct with wasmPlugin *extism.Plugin field
  • Removes the need for string key constants (wasmStateKey)
  • Eliminates runtime type assertions when accessing the plugin
  • Improves type safety and code readability
  • Updates all related tests to use the new fasState type

The refactoring simplifies the code by making the state structure explicit and compile-time checked, reducing potential runtime errors from incorrect type assertions or missing keys.

Which issue(s) this PR fixes:

Cleanup on #4080

Special notes for your reviewer:

Now this is refactored, I'm going to move the http client for the webhook autoscaler into this state, which will simply cert management (and also fix a bug I just found).

Replace the generic map[string]any state in fasThread with a typed
fasState struct containing a wasmPlugin field. This change:

- Introduces fasState struct with wasmPlugin *extism.Plugin field
- Removes the need for string key constants (wasmStateKey)
- Eliminates runtime type assertions when accessing the plugin
- Improves type safety and code readability
- Updates all related tests to use the new fasState type

The refactoring simplifies the code by making the state structure
explicit and compile-time checked, reducing potential runtime errors
from incorrect type assertions or missing keys.
@markmandel markmandel added the kind/cleanup Refactoring code, fixing up documentation, etc label Oct 27, 2025
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the FleetAutoscaler state management from a generic map[string]any to a typed fasState struct for improved type safety and code clarity. The changes eliminate runtime type assertions and string key constants, replacing them with compile-time checked struct fields.

Key Changes:

  • Introduced fasState struct with a wasmPlugin field to replace the generic state map
  • Removed the wasmStateKey constant and associated string-based map lookups
  • Simplified cleanup logic in fasThread.close() by removing nested type assertions

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/fleetautoscalers/controller.go Introduced fasState struct and updated fasThread to use typed state
pkg/fleetautoscalers/fleetautoscalers.go Updated function signatures to accept fasState and simplified plugin access
pkg/fleetautoscalers/controller_test.go Updated test initialization to use fasState{}
pkg/fleetautoscalers/fleetautoscalers_test.go Updated test calls to use fasState{}
pkg/fleetautoscalers/fleetautoscalerwasm_test.go Updated test initialization to use fasState{}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return 0, false, errors.Wrapf(err, "failed to create Wasm plugin from %s", u.String())
}
state[wasmStateKey] = plugin // Store the plugin in the state map
state.wasmPlugin = plugin // Store the plugin in the state map
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment 'Store the plugin in the state map' is outdated since the state is no longer a map. Consider updating to 'Store the plugin in the state'.

Suggested change
state.wasmPlugin = plugin // Store the plugin in the state map
state.wasmPlugin = plugin // Store the plugin in the state

Copilot uses AI. Check for mistakes.

_, ok := state[wasmStateKey]
if !ok {
if state.wasmPlugin == nil {
Copy link

Copilot AI Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fasState is passed by value, so modifications to state.wasmPlugin inside this function will not persist to the caller. The function should accept *fasState (pointer) instead to allow the plugin to be stored and reused across calls.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was debating this. It's a good point, I'll make this change.

@agones-bot
Copy link
Copy Markdown
Collaborator

Build Succeeded 🥳

Build Id: 028aa99d-0cb0-460a-b80f-7ee4bc94e554

The following development artifacts have been built, and will exist for the next 30 days:

A preview of the website (the last 30 builds are retained):

To install this version:

git fetch https://github.com/googleforgames/agones.git pull/4315/head:pr_4315 && git checkout pr_4315
helm install agones ./install/helm/agones --namespace agones-system --set agones.image.registry=us-docker.pkg.dev/agones-images/ci --set agones.image.tag=1.54.0-dev-a057f3d

@markmandel
Copy link
Copy Markdown
Collaborator Author

Definitely something flaky with this test. Is it just autopilot though? Seems to be 🤔

https://console.cloud.google.com/cloud-build/builds/bd31769b-80a0-46e5-a0c7-955589603b08;step=1?project=agones-images

FAIL test/e2e/allocator.TestAllocatorAfterDeleteReplica (-1.00s)

=== Failed
=== FAIL: test/e2e/allocator  (0.00s)
time="2025-10-28 03:49:46.991" level=warning msg="Error creating inClusterConfig, trying to build config from flagsunable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined" error="unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined" source=framework
time="2025-10-28 03:49:47.000" level=info msg="Starting e2e test(s)" cloudProduct=gke-autopilot featureGates="AutopilotPassthroughPort=false&CountsAndLists=false&DisableResyncOnSDKServer=true&Example=true&FleetAutoscaleRequestMetaData=true&GKEAutopilotExtendedDurationPods=false&PlayerAllocationFilter=true&PlayerTracking=true&PortPolicyNone=false&PortRanges=false&ProcessorAllocator=false&RollingUpdateFix=false&ScheduledAutoscaler=false&SidecarContainers=true&WasmAutoscaler=true" gameServerImage="us-docker.pkg.dev/agones-images/examples/simple-game-server:0.39" namespace= perfOutputDir= pullSecret= stressTestLevel=0 version=
time="2025-10-28 03:49:47.090" level=info msg="Custom namespace is set: 1761623387"
time="2025-10-28 03:49:47.135" level=info msg="Namespace 1761623387 is created"
time="2025-10-28 03:49:47.195" level=info msg="ServiceAccount 1761623387/agones-sdk is created"
time="2025-10-28 03:49:47.262" level=info msg="RoleBinding 1761623387/agones-sdk-access is created"
panic: test timed out after 10m0s
	running tests:
		TestAllocatorAfterDeleteReplica (10m0s)

goroutine 90 [running]:
testing.(*M).startAlarm.func1()
	/usr/local/go/src/testing/testing.go:2484 +0x605
created by time.goFunc
	/usr/local/go/src/time/sleep.go:215 +0x45

goroutine 1 [chan receive, 10 minutes]:
testing.(*T).Run(0xc0001056c0, {0x2f71bc3, 0x1f}, 0x304e530)
	/usr/local/go/src/testing/testing.go:1859 +0x91e
testing.runTests.func1(0xc0001056c0)
	/usr/local/go/src/testing/testing.go:2279 +0x86
testing.tRunner(0xc0001056c0, 0xc0005b98c8)
	/usr/local/go/src/testing/testing.go:1792 +0x226
testing.runTests(0xc0002276c8, {0x4465860, 0x1, 0x1}, {0xc0005b9940?, 0x44b894?, 0x449ae40?})
	/usr/local/go/src/testing/testing.go:2277 +0x96d
testing.(*M).Run(0xc0003fadc0)
	/usr/local/go/src/testing/testing.go:2142 +0xeeb
agones.dev/agones/test/e2e/allocator.TestMain(0xc0003fadc0)
	/go/src/agones.dev/agones/test/e2e/allocator/main_test.go:91 +0xa85
main.main()
	_testmain.go:47 +0x172

/gcbrun

@lacroixthomas
Copy link
Copy Markdown
Collaborator

/gcbrun

Copy link
Copy Markdown
Collaborator

@lacroixthomas lacroixthomas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM !
Looks cleaner this way compared to a map that needs some casting etc. 👌🏼

From your comment on the PR, I'm wondering the issue you found, to move the http client into the state ! Shall see from the next review hehe

@markmandel markmandel merged commit 14424a5 into agones-dev:main Oct 31, 2025
4 checks passed
@markmandel markmandel deleted the cleanup/fas-state branch October 31, 2025 00:16
@agones-bot
Copy link
Copy Markdown
Collaborator

Build Failed 😭

Build Id: 34d90638-9b47-46c4-9fd8-0f82ce605ce4

Status: FAILURE

To get permission to view the Cloud Build view, join the agones-discuss Google Group.

@agones-bot
Copy link
Copy Markdown
Collaborator

Build Failed 😭

Build Id: 07c030e7-dda5-4e93-9b07-ab22f697d6fc

Status: FAILURE

To get permission to view the Cloud Build view, join the agones-discuss Google Group.

@agones-bot
Copy link
Copy Markdown
Collaborator

Build Succeeded 🥳

Build Id: b372d325-ee0c-4b1a-a0f3-9ce967613bbd

The following development artifacts have been built, and will exist for the next 30 days:

A preview of the website (the last 30 builds are retained):

To install this version:

git fetch https://github.com/googleforgames/agones.git pull/4315/head:pr_4315 && git checkout pr_4315
helm install agones ./install/helm/agones --namespace agones-system --set agones.image.registry=us-docker.pkg.dev/agones-images/ci --set agones.image.tag=1.54.0-dev-0095596

mnthe pushed a commit to mnthe/agones that referenced this pull request Mar 23, 2026
)

* Refactor FleetAutoscaler state from map to typed struct

Replace the generic map[string]any state in fasThread with a typed
fasState struct containing a wasmPlugin field. This change:

- Introduces fasState struct with wasmPlugin *extism.Plugin field
- Removes the need for string key constants (wasmStateKey)
- Eliminates runtime type assertions when accessing the plugin
- Improves type safety and code readability
- Updates all related tests to use the new fasState type

The refactoring simplifies the code by making the state structure
explicit and compile-time checked, reducing potential runtime errors
from incorrect type assertions or missing keys.

* Review updates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/cleanup Refactoring code, fixing up documentation, etc size/S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants