locust-cloud 1.5.8__py3-none-any.whl → 1.5.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
locust_cloud/__init__.py CHANGED
@@ -66,7 +66,7 @@ def create_connection_pool(
66
66
  return ConnectionPool(
67
67
  conninfo=f"postgres://{pg_user}:{pg_password}@{pg_host}:{pg_port}/{pg_database}?sslmode=require",
68
68
  min_size=1,
69
- max_size=5,
69
+ max_size=10,
70
70
  configure=set_autocommit,
71
71
  )
72
72
  except Exception:
locust_cloud/cloud.py CHANGED
@@ -64,22 +64,28 @@ parser = configargparse.ArgumentParser(
64
64
  configargparse.DefaultConfigFileParser,
65
65
  ]
66
66
  ),
67
- description="""Launches distributed Locust runs on locust.cloud infrastructure.
67
+ description="""Launches a distributed Locust runs on locust.cloud infrastructure.
68
68
 
69
- Example: locust-cloud -f my_locustfile.py --region us-east-1 --users 2000""",
69
+ Example: locust-cloud -f my_locustfile.py --users 1000 ...""",
70
70
  epilog="""Any parameters not listed here are forwarded to locust master unmodified, so go ahead and use things like --users, --host, --run-time, ...
71
71
  Locust config can also be set using config file (~/.locust.conf, locust.conf, pyproject.toml, ~/.cloud.conf or cloud.conf).
72
72
  Parameters specified on command line override env vars, which in turn override config files.""",
73
73
  add_config_file_help=False,
74
74
  add_env_var_help=False,
75
+ add_help=False,
76
+ )
77
+ parser.add_argument(
78
+ "-h",
79
+ "--help",
80
+ action="help",
81
+ help=configargparse.SUPPRESS,
75
82
  )
76
-
77
83
  parser.add_argument(
78
84
  "-f",
79
85
  "--locustfile",
80
86
  metavar="<filename>",
81
87
  default="locustfile.py",
82
- help="The Python file or module that contains your test, e.g. 'my_test.py'. Defaults to 'locustfile.py'.",
88
+ help="The Python file that contains your test. Defaults to 'locustfile.py'.",
83
89
  env_var="LOCUST_LOCUSTFILE",
84
90
  )
85
91
  parser.add_argument(
@@ -90,29 +96,37 @@ parser.add_argument(
90
96
  help="Number of users to launch. This is the same as the regular Locust argument, but also affects how many workers to launch.",
91
97
  env_var="LOCUST_USERS",
92
98
  )
93
- parser.add_argument(
99
+ advanced = parser.add_argument_group("advanced")
100
+ advanced.add_argument(
101
+ "--loglevel",
102
+ "-L",
103
+ type=str,
104
+ help="Set --loglevel DEBUG for extra info.",
105
+ default="INFO",
106
+ )
107
+ advanced.add_argument(
94
108
  "--requirements",
95
109
  type=str,
96
110
  help="Optional requirements.txt file that contains your external libraries.",
97
111
  )
98
- parser.add_argument(
112
+ advanced.add_argument(
99
113
  "--region",
100
114
  type=str,
101
115
  default=os.environ.get("AWS_DEFAULT_REGION", DEFAULT_REGION_NAME),
102
116
  help="Sets the AWS region to use for the deployed cluster, e.g. us-east-1. It defaults to use AWS_DEFAULT_REGION env var, like AWS tools.",
103
117
  )
104
- parser.add_argument(
118
+ advanced.add_argument(
105
119
  "--kube-cluster-name",
106
120
  type=str,
107
121
  default=DEFAULT_CLUSTER_NAME,
108
- help="Sets the name of the Kubernetes cluster",
122
+ help=configargparse.SUPPRESS,
109
123
  env_var="KUBE_CLUSTER_NAME",
110
124
  )
111
- parser.add_argument(
125
+ advanced.add_argument(
112
126
  "--kube-namespace",
113
127
  type=str,
114
128
  default=DEFAULT_NAMESPACE,
115
- help="Sets the namespace for scoping the deployed cluster",
129
+ help=configargparse.SUPPRESS,
116
130
  env_var="KUBE_NAMESPACE",
117
131
  )
118
132
  parser.add_argument(
@@ -138,26 +152,19 @@ parser.add_argument(
138
152
  parser.add_argument(
139
153
  "--username",
140
154
  type=str,
141
- help="Authentication for deploying with Locust Cloud",
155
+ help=configargparse.SUPPRESS,
142
156
  default=os.getenv("LOCUST_CLOUD_USERNAME", None), # backwards compatitibility for dmdb
143
157
  )
144
158
  parser.add_argument(
145
159
  "--password",
146
160
  type=str,
147
- help="Authentication for deploying with Locust Cloud",
161
+ help=configargparse.SUPPRESS,
148
162
  default=os.getenv("LOCUST_CLOUD_PASSWORD", None), # backwards compatitibility for dmdb
149
163
  )
150
- parser.add_argument(
151
- "--loglevel",
152
- "-L",
153
- type=str,
154
- help="Log level",
155
- default="INFO",
156
- )
157
164
  parser.add_argument(
158
165
  "--workers",
159
166
  type=int,
160
- help=f"Number of workers to use for the deployment. Defaults to number of users divided by {USERS_PER_WORKER}",
167
+ help=f"Number of workers to use for the deployment. Defaults to number of users divided by {USERS_PER_WORKER}.",
161
168
  default=None,
162
169
  )
163
170
  parser.add_argument(
@@ -230,6 +237,7 @@ def main() -> None:
230
237
  return
231
238
 
232
239
  logger.info(f"Uploading {options.locustfile}")
240
+ logger.debug(f"... to {s3_bucket}")
233
241
  s3 = credential_manager.session.client("s3")
234
242
  try:
235
243
  s3.upload_file(options.locustfile, s3_bucket, os.path.basename(options.locustfile))
@@ -318,6 +326,9 @@ def main() -> None:
318
326
  except CredentialError as ce:
319
327
  logger.error(f"Credential error: {ce}")
320
328
  sys.exit(1)
329
+ except KeyboardInterrupt:
330
+ logger.debug("Interrupted by user")
331
+ sys.exit(0)
321
332
 
322
333
  log_group_name = f"/eks/{options.kube_cluster_name}-{options.kube_namespace}"
323
334
  master_pod_name = next((pod for pod in deployed_pods if "master" in pod), None)
@@ -410,9 +421,10 @@ def delete(s3_bucket, credential_manager):
410
421
  )
411
422
 
412
423
  if response.status_code != 200:
413
- logger.error(
424
+ logger.info(
414
425
  f"Could not automatically tear down Locust Cloud: HTTP {response.status_code}/{response.reason} - Response: {response.text} - URL: {response.request.url}"
415
426
  )
427
+ logger.debug(response.json()["message"])
416
428
  except Exception as e:
417
429
  logger.error(f"Could not automatically tear down Locust Cloud: {e.__class__.__name__}:{e}")
418
430
 
@@ -12,6 +12,7 @@ import locust.env
12
12
  import psycopg
13
13
  import psycopg.types.json
14
14
  from locust.exception import CatchResponseError
15
+ from locust.runners import MasterRunner
15
16
 
16
17
 
17
18
  def safe_serialize(obj):
@@ -185,11 +186,19 @@ class Exporter:
185
186
  cmd = sys.argv[1:]
186
187
  with self.pool.connection() as conn:
187
188
  conn.execute(
188
- "INSERT INTO testruns (id, num_users, description, arguments) VALUES (%s,%s,%s,%s)",
189
+ "INSERT INTO testruns (id, num_users, worker_count, username, locustfile, description, arguments) VALUES (%s,%s,%s,%s,%s,%s,%s)",
189
190
  (
190
191
  self._run_id,
191
192
  self.env.runner.target_user_count if self.env.runner else 1,
192
- "self.env.parsed_options.description",
193
+ len(self.env.runner.clients)
194
+ if isinstance(
195
+ self.env.runner,
196
+ MasterRunner,
197
+ )
198
+ else 0,
199
+ self.env.web_ui.template_args.get("username", "") if self.env.web_ui else "",
200
+ self.env.parsed_locustfiles[0].split("/")[-1],
201
+ self.env.parsed_options.description,
193
202
  " ".join(cmd),
194
203
  ),
195
204
  )
@@ -198,7 +198,10 @@ SELECT
198
198
  requests,
199
199
  date_trunc('second', end_time - id) AS "runTime",
200
200
  description,
201
- exit_code as "exitCode"
201
+ exit_code as "exitCode",
202
+ username,
203
+ worker_count as "workerCount",
204
+ locustfile
202
205
  FROM testruns
203
206
  ORDER BY id DESC
204
207
  """
@@ -261,7 +264,7 @@ total_runtime = """
261
264
  SELECT
262
265
  SUM((end_time - id) * num_users) AS "totalVuh"
263
266
  FROM testruns
264
- WHERE id >= date_trunc('month', NOW())
267
+ WHERE id >= date_trunc('month', NOW()) AND NOT refund
265
268
  """
266
269
 
267
270
  queries: dict["str", LiteralString] = {
@@ -59,5 +59,5 @@ def register_query(environment, pool):
59
59
  logger.warning(f"Received invalid query key: '{query}'")
60
60
  return make_response("Invalid query key", 401)
61
61
  except Exception as e:
62
- logger.error(f"Error executing query '{query}': {e}", exc_info=True)
62
+ logger.info(f"Error executing UI query '{query}': {e}", exc_info=True)
63
63
  return make_response("Error executing query", 401)