Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix externally-controlled maxVUs scaling #1517

Merged
merged 7 commits into from
Jun 30, 2020

Conversation

imiric
Copy link
Contributor

@imiric imiric commented Jun 24, 2020

Closes #1511

I'm not sure this is the right fix, and the test is a bit hacky, but let me know.

@imiric imiric requested review from mstoykov and na-- June 24, 2020 15:39
if updateErr := executor.UpdateConfig(r.Context(), newConfig); err != nil {
apiError(rw, "Config update error", updateErr.Error(), http.StatusInternalServerError)
if updateErr := executor.UpdateConfig(r.Context(), newConfig); updateErr != nil {
apiError(rw, "Config update error", updateErr.Error(), http.StatusBadRequest)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mstoykov We need that errorcheck linter ;)

Also note the change to a 400 response code here, which is what was expected by the test, and will probably make sense in most cases.

@@ -479,6 +479,7 @@ func (rs *externallyControlledRunState) handleConfigChange(oldCfg, newCfg Extern
executionState.ReturnVU(rs.vuHandles[i].initVU, false)
}
rs.vuHandles[i] = nil
executionState.ModInitializedVUsCount(-1)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was this the actual issue of not scaling down ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes :D initializedVUs wasn't decremented anywhere. Though not sure if this is the right approach or place for it :-/

Copy link
Member

Choose a reason for hiding this comment

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

This should only be done when we're not returning the VU back to the buffer pool though, like this:

			if i < rs.startMaxVUs {
				// return the initial planned VUs to the common buffer
				executionState.ReturnVU(rs.vuHandles[i].initVU, false)
			} else {
				executionState.ModInitializedVUsCount(-1)
			}

Copy link
Member

Choose a reason for hiding this comment

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

To demonstrate, use the following options:

export let options = {
    scenarios: {
        extc1: {
            executor: "externally-controlled",
            vus: 5,
            maxVUs: 10,
            duration: "10s",
        },
        const_loop_vus: {
            executor: "constant-vus",
            vus: 10,
            duration: "20s",
            startTime: "10s",
            gracefulStop: "0s",
        },
    },
};

see the 00/00 VUs in the description here:

running (14.1s), 00/00 VUs, 139 complete and 15 interrupted iterations
extc1          ✓ [======================================] 05/10 VUs  10s   
const_loop_vus ✗ [======>-------------------------------] 10 VUs     04.1s/20s

Ivan Mirić added 3 commits June 25, 2020 12:35
This replicates more closely what the local ExecutionScheduler does, and
is needed for correct assertions in externally-controlled tests.
@imiric imiric force-pushed the fix/1511-external-scale branch 3 times, most recently from 8d04ad7 to a246679 Compare June 25, 2020 15:13
@codecov-commenter
Copy link

codecov-commenter commented Jun 25, 2020

Codecov Report

Merging #1517 into new-schedulers will increase coverage by 0.58%.
The diff coverage is 85.71%.

Impacted file tree graph

@@                Coverage Diff                 @@
##           new-schedulers    #1517      +/-   ##
==================================================
+ Coverage           76.64%   77.23%   +0.58%     
==================================================
  Files                 163      163              
  Lines               13044    13046       +2     
==================================================
+ Hits                 9998    10076      +78     
+ Misses               2532     2454      -78     
- Partials              514      516       +2     
Impacted Files Coverage Δ
api/v1/status_routes.go 55.10% <66.66%> (+44.89%) ⬆️
lib/executor/externally_controlled.go 76.12% <100.00%> (+14.80%) ⬆️
lib/executors.go 94.11% <0.00%> (+1.96%) ⬆️
lib/executor/helpers.go 96.70% <0.00%> (+2.19%) ⬆️
core/local/local.go 76.21% <0.00%> (+2.20%) ⬆️
lib/execution.go 93.89% <0.00%> (+2.29%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a9903e0...d84fe0e. Read the comment docs.

@imiric
Copy link
Contributor Author

imiric commented Jun 25, 2020

Phew, I think TestExternallyControlledRun should finally be flake-free 🤞 See fc48c46.

I'll see if I can apply this same pattern to other executor tests to stabilize them. We should preferably have something like a MiniExecutionScheduler 😄 that would standardize a stable test structure and maybe allow inspection and expose some test helpers.

@@ -479,6 +479,7 @@ func (rs *externallyControlledRunState) handleConfigChange(oldCfg, newCfg Extern
executionState.ReturnVU(rs.vuHandles[i].initVU, false)
}
rs.vuHandles[i] = nil
executionState.ModInitializedVUsCount(-1)
Copy link
Member

Choose a reason for hiding this comment

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

This should only be done when we're not returning the VU back to the buffer pool though, like this:

			if i < rs.startMaxVUs {
				// return the initial planned VUs to the common buffer
				executionState.ReturnVU(rs.vuHandles[i].initVU, false)
			} else {
				executionState.ModInitializedVUsCount(-1)
			}

@imiric
Copy link
Contributor Author

imiric commented Jun 30, 2020

@na-- See 64f30fc with that change.

Though there are still some inconsistencies:

  1. If two executors are started, for example:
import http from 'k6/http';
import { sleep } from 'k6';

export let options = {
  scenarios: {
    adjustable_at_will: {
      executor: 'externally-controlled',
      vus: 0,
      maxVUs: 10,
      duration: '10m',
    },
    constant_vus: {
      executor: 'constant-vus',
      vus: 20,
      duration: '2m',
    },
  }
};

export default function() {
  sleep(0.2);
}
  1. k6 status returns vus: "20", vus-max: "30", taking into account the global counts.

  2. Yet trying k6 scale -u 30 will of course error out because of the 10 maxVUs configured for the externally-controlled exec. Similarly with scale -m, etc.

It's somewhat confusing that the API returns the global status, but can only modify externally-controlled parameters. Not sure how big of a problem this would be in practice, though it would be best to avoid any such inconsistencies. Maybe transparently convert any scale values to the externally-controlled config (i.e. -u 30 actually becomes -u 10)? Or do you think just documenting this would be enough?

Copy link
Collaborator

@mstoykov mstoykov left a comment

Choose a reason for hiding this comment

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

LGTM, but I haven't tried it locally

@imiric imiric requested a review from na-- June 30, 2020 09:10
@imiric
Copy link
Contributor Author

imiric commented Jun 30, 2020

#1357 strikes again 😞

@na--
Copy link
Member

na-- commented Jun 30, 2020

hmm I think we should just document this, and fix it in the v2 REST API, whenever that is implemented...

@imiric
Copy link
Contributor Author

imiric commented Jun 30, 2020

OK, I'll mention it in the release notes and the new docs somewhere.

@imiric imiric merged commit 890270d into new-schedulers Jun 30, 2020
@imiric imiric deleted the fix/1511-external-scale branch June 30, 2020 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants