|
19 | 19 | --enterprise-uuid=<uuid> \ |
20 | 20 | --output-file=local-enrollment-output.csv \ |
21 | 21 | --environment=local \ |
22 | | - --sleep-interval=5 \ |
23 | 22 | --fetch-jwt |
24 | 23 | ``` |
25 | 24 |
|
|
30 | 29 | * ``--enterprise-uuid`` The UUID of the enterprise to which all enrollments are associated. |
31 | 30 |
|
32 | 31 | * ``--output-file`` is where results of the call to the bulk-license-enrollment view are stored. It'll be a headerless |
33 | | -CSV with three columns: ``chunk_id``, ``job_id``, ``email``. |
| 32 | +CSV with three columns: ``chunk_id``, ``job_id``, ``email``, ``job_results_url``. |
34 | 33 |
|
35 | 34 | * ``--chunk-size`` Number of emails contained in each chunk. Default and max is 1000. |
36 | 35 |
|
37 | 36 | * ``--environment`` Which environment to execute against. Choices are 'local', 'stage', or 'prod'. |
38 | 37 |
|
39 | | -* ``--sleep-interval`` is how long to wait between chunk deliveries, in seconds. Each chunk of this script causes one |
40 | | -asynchronous bulk enrollment task to be queued, so this interval is the primary way of controlling concurrency. If |
41 | | -``--sleep-interval`` is too high, operational risk is low but enrollment of all learners may take too long. If |
42 | | -``--sleep-interval`` is too low, a couple of risks arise: 1) we risk overwhelming the license_manager.bulk_enrollment |
43 | | -dedicated celery queue, and 2) completion rate may be slower than task creation, increasing risk of accumulating more |
44 | | -failed tasks before manually terminating the script. |
| 38 | +* ``--sleep-interval`` is how long to wait between chunk deliveries, in seconds (default = 120). Each chunk of this |
| 39 | +script causes one asynchronous bulk enrollment task to be queued, so this interval is the primary way of controlling |
| 40 | +concurrency. If ``--sleep-interval`` is too high, operational risk is low but enrollment of all learners may take too |
| 41 | +long. If ``--sleep-interval`` is too low, a couple of risks arise: 1) we risk overwhelming the |
| 42 | +license_manager.bulk_enrollment dedicated celery queue, and 2) completion rate may be slower than task creation, |
| 43 | +increasing risk of accumulating more failed tasks before manually terminating the script. |
45 | 44 | """ |
46 | 45 | from collections import defaultdict |
47 | 46 | import csv |
|
50 | 49 |
|
51 | 50 | import click |
52 | 51 | import requests |
| 52 | +from requests.models import PreparedRequest |
53 | 53 |
|
54 | 54 |
|
55 | 55 | # 1000 is currently the maximum number of emails allowed by the bulk-license-enrollment API endpoint. (I didn't actually |
@@ -112,7 +112,7 @@ def get_already_processed_emails(results_file): |
112 | 112 | already_processed_emails = {} |
113 | 113 | with open(results_file, 'r') as f_in: |
114 | 114 | reader = csv.reader(f_in, delimiter=',') |
115 | | - for (chunk_id, _, email_address) in reader: |
| 115 | + for (chunk_id, _, email_address, _) in reader: |
116 | 116 | already_processed_emails[email_address] = chunk_id |
117 | 117 | return already_processed_emails |
118 | 118 |
|
@@ -220,18 +220,32 @@ def request_enrollments( |
220 | 220 |
|
221 | 221 | response_data = response.json() |
222 | 222 |
|
| 223 | + # Use the requests library to generate a URL to fetch job results, but not actually call it. |
| 224 | + req = PreparedRequest() |
| 225 | + req.prepare_url( |
| 226 | + url, |
| 227 | + { |
| 228 | + 'enterprise_customer_uuid': enterprise_uuid, |
| 229 | + 'bulk_enrollment_job_uuid': response_data['job_id'], |
| 230 | + }, |
| 231 | + ) |
| 232 | + job_results_url = req.url |
| 233 | + |
223 | 234 | results_for_chunk = [] |
224 | 235 | for email in emails_for_chunk: |
225 | 236 | results_for_chunk.append([ |
226 | 237 | str(chunk_id), |
227 | 238 | str(response_data['job_id']), |
228 | 239 | email, |
| 240 | + job_results_url, |
229 | 241 | ]) |
230 | 242 |
|
231 | | - print('Generated BulkEnrollmentJob UUID:', response_data['job_id']) |
232 | 243 | print( |
233 | | - f'Successfully sent bulk enrollment request for chunk_id {chunk_id} and course_run_key {course_run_key} with ' |
234 | | - f'{len(emails_for_chunk)} emails' |
| 244 | + f'Successfully sent bulk enrollment request containing {len(emails_for_chunk)} emails. ' |
| 245 | + f'chunk_id = {chunk_id}, ' |
| 246 | + f'course_run_key = {course_run_key}, ' |
| 247 | + f'BulkEnrollmentJob UUID = {response_data["job_id"]}, ' |
| 248 | + f'job results URL = {job_results_url}' |
235 | 249 | ) |
236 | 250 |
|
237 | 251 | return results_for_chunk |
@@ -275,7 +289,14 @@ def do_enrollment_for_chunk( |
275 | 289 | print(f'Sleeping for {sleep_interval} seconds.') |
276 | 290 | time.sleep(sleep_interval) |
277 | 291 | else: |
278 | | - print('No enrollments need to be created for chunk_id', chunk_id, 'with size', len(email_chunk)) |
| 292 | + print( |
| 293 | + 'No enrollments need to be created for chunk_id', |
| 294 | + chunk_id, |
| 295 | + 'with size', |
| 296 | + len(email_chunk), |
| 297 | + 'and course_run_key', |
| 298 | + course_run_key, |
| 299 | + ) |
279 | 300 |
|
280 | 301 |
|
281 | 302 | @click.command() |
|
0 commit comments