aio-sf 0.1.0b8__py3-none-any.whl → 0.1.0b10__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.
- aio_sf/api/collections/__init__.py +3 -3
- aio_sf/api/collections/batch.py +104 -45
- aio_sf/api/collections/client.py +13 -13
- {aio_sf-0.1.0b8.dist-info → aio_sf-0.1.0b10.dist-info}/METADATA +30 -10
- {aio_sf-0.1.0b8.dist-info → aio_sf-0.1.0b10.dist-info}/RECORD +7 -7
- {aio_sf-0.1.0b8.dist-info → aio_sf-0.1.0b10.dist-info}/WHEEL +0 -0
- {aio_sf-0.1.0b8.dist-info → aio_sf-0.1.0b10.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Salesforce Collections API module."""
|
|
2
2
|
|
|
3
3
|
from .client import CollectionsAPI
|
|
4
|
-
from .batch import
|
|
4
|
+
from .batch import ResultInfo, ResultCallback
|
|
5
5
|
from .retry import ShouldRetryCallback, default_should_retry
|
|
6
6
|
from .types import (
|
|
7
7
|
CollectionError,
|
|
@@ -14,8 +14,8 @@ from .types import (
|
|
|
14
14
|
|
|
15
15
|
__all__ = [
|
|
16
16
|
"CollectionsAPI",
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"ResultInfo",
|
|
18
|
+
"ResultCallback",
|
|
19
19
|
"ShouldRetryCallback",
|
|
20
20
|
"default_should_retry",
|
|
21
21
|
"CollectionError",
|
aio_sf/api/collections/batch.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
|
-
from typing import Any, Awaitable, Callable, List, Optional, TypedDict, Union
|
|
5
|
+
from typing import Any, Awaitable, Callable, Dict, List, Optional, TypedDict, Union
|
|
6
6
|
|
|
7
7
|
from .retry import (
|
|
8
8
|
RecordWithAttempt,
|
|
@@ -17,19 +17,25 @@ from .types import CollectionResult
|
|
|
17
17
|
logger = logging.getLogger(__name__)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
class
|
|
21
|
-
"""
|
|
20
|
+
class ResultInfo(TypedDict):
|
|
21
|
+
"""Result information provided after each batch completes."""
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
successes: List[CollectionResult] # Successful results from this batch
|
|
24
|
+
errors: List[
|
|
25
|
+
CollectionResult
|
|
26
|
+
] # Failed results from this batch (API and HTTP errors)
|
|
27
|
+
total_records: int # Total records being processed
|
|
28
|
+
records_completed: int # Records finished (succeeded or failed permanently)
|
|
29
|
+
records_succeeded: int # Records that succeeded so far
|
|
30
|
+
records_failed: int # Records that failed permanently so far
|
|
31
|
+
records_pending: int # Records still being retried
|
|
32
|
+
current_attempt: int # Current retry attempt number (1-indexed)
|
|
33
|
+
current_batch_size: int # Batch size for current attempt
|
|
34
|
+
current_concurrency: int # Concurrency level for current attempt
|
|
29
35
|
|
|
30
36
|
|
|
31
|
-
# Type alias for
|
|
32
|
-
|
|
37
|
+
# Type alias for result callback
|
|
38
|
+
ResultCallback = Callable[[ResultInfo], Awaitable[None]]
|
|
33
39
|
|
|
34
40
|
|
|
35
41
|
def split_into_batches(
|
|
@@ -63,7 +69,9 @@ async def process_batches_concurrently(
|
|
|
63
69
|
operation_func,
|
|
64
70
|
max_concurrent_batches: int,
|
|
65
71
|
total_records: int,
|
|
66
|
-
|
|
72
|
+
on_result: Optional[ResultCallback] = None,
|
|
73
|
+
progress_state: Optional[Dict[str, int]] = None,
|
|
74
|
+
final_results: Optional[List] = None,
|
|
67
75
|
*args,
|
|
68
76
|
**kwargs,
|
|
69
77
|
) -> List[Any]:
|
|
@@ -77,7 +85,8 @@ async def process_batches_concurrently(
|
|
|
77
85
|
:param operation_func: Function to call for each batch
|
|
78
86
|
:param max_concurrent_batches: Maximum number of concurrent batch operations
|
|
79
87
|
:param total_records: Total number of records being processed
|
|
80
|
-
:param
|
|
88
|
+
:param on_result: Optional callback invoked after each batch completes with results
|
|
89
|
+
:param progress_state: Dict with progress state (to include in callback)
|
|
81
90
|
:param args: Additional positional arguments for operation_func
|
|
82
91
|
:param kwargs: Additional keyword arguments for operation_func
|
|
83
92
|
:returns: List of results from all batches in the same order as input
|
|
@@ -87,12 +96,9 @@ async def process_batches_concurrently(
|
|
|
87
96
|
raise ValueError("max_concurrent_batches must be greater than 0")
|
|
88
97
|
|
|
89
98
|
semaphore = asyncio.Semaphore(max_concurrent_batches)
|
|
90
|
-
|
|
91
|
-
callback_lock = asyncio.Lock() if on_batch_complete else None
|
|
92
|
-
records_processed = 0
|
|
99
|
+
callback_lock = asyncio.Lock() if on_result else None
|
|
93
100
|
|
|
94
101
|
async def process_batch_with_semaphore(batch_index: int, batch):
|
|
95
|
-
nonlocal records_processed
|
|
96
102
|
async with semaphore:
|
|
97
103
|
try:
|
|
98
104
|
result = await operation_func(batch, *args, **kwargs)
|
|
@@ -103,20 +109,52 @@ async def process_batches_concurrently(
|
|
|
103
109
|
)
|
|
104
110
|
result = [e for _ in range(len(batch))]
|
|
105
111
|
|
|
106
|
-
# Invoke
|
|
107
|
-
if
|
|
108
|
-
batch_size = len(batch)
|
|
112
|
+
# Invoke callback if provided, with results and progress state
|
|
113
|
+
if on_result and callback_lock and progress_state:
|
|
109
114
|
async with callback_lock:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
# Split results into successes and errors
|
|
116
|
+
successes: List[CollectionResult] = []
|
|
117
|
+
errors: List[CollectionResult] = []
|
|
118
|
+
|
|
119
|
+
for item in result:
|
|
120
|
+
# Convert exceptions to CollectionResult format
|
|
121
|
+
if isinstance(item, Exception):
|
|
122
|
+
error_result = convert_exception_to_result(item)
|
|
123
|
+
errors.append(error_result)
|
|
124
|
+
elif item.get("success", False):
|
|
125
|
+
successes.append(item)
|
|
126
|
+
else:
|
|
127
|
+
errors.append(item)
|
|
128
|
+
|
|
129
|
+
# Compute current counts dynamically from final_results
|
|
130
|
+
if final_results:
|
|
131
|
+
records_succeeded = sum(
|
|
132
|
+
1
|
|
133
|
+
for r in final_results
|
|
134
|
+
if r is not None and r.get("success", False)
|
|
135
|
+
)
|
|
136
|
+
records_failed = sum(
|
|
137
|
+
1
|
|
138
|
+
for r in final_results
|
|
139
|
+
if r is not None and not r.get("success", False)
|
|
140
|
+
)
|
|
141
|
+
records_completed = records_succeeded + records_failed
|
|
142
|
+
else:
|
|
143
|
+
records_succeeded = records_failed = records_completed = 0
|
|
144
|
+
|
|
145
|
+
result_info: ResultInfo = {
|
|
146
|
+
"successes": successes,
|
|
147
|
+
"errors": errors,
|
|
148
|
+
"total_records": progress_state["total_records"],
|
|
149
|
+
"records_completed": records_completed,
|
|
150
|
+
"records_succeeded": records_succeeded,
|
|
151
|
+
"records_failed": records_failed,
|
|
152
|
+
"records_pending": progress_state["records_pending"],
|
|
153
|
+
"current_attempt": progress_state["current_attempt"],
|
|
154
|
+
"current_batch_size": progress_state["current_batch_size"],
|
|
155
|
+
"current_concurrency": progress_state["current_concurrency"],
|
|
118
156
|
}
|
|
119
|
-
await
|
|
157
|
+
await on_result(result_info)
|
|
120
158
|
|
|
121
159
|
return result
|
|
122
160
|
|
|
@@ -140,7 +178,7 @@ async def process_with_retries(
|
|
|
140
178
|
max_attempts: int,
|
|
141
179
|
should_retry_callback: Optional[ShouldRetryCallback],
|
|
142
180
|
max_concurrent_batches: Union[int, List[int]],
|
|
143
|
-
|
|
181
|
+
on_result: Optional[ResultCallback],
|
|
144
182
|
max_limit: int,
|
|
145
183
|
*args,
|
|
146
184
|
**kwargs,
|
|
@@ -154,7 +192,7 @@ async def process_with_retries(
|
|
|
154
192
|
:param max_attempts: Maximum number of attempts per record
|
|
155
193
|
:param should_retry_callback: Optional callback to determine if record should be retried
|
|
156
194
|
:param max_concurrent_batches: Maximum concurrent batches (int or list of ints per attempt)
|
|
157
|
-
:param
|
|
195
|
+
:param on_result: Callback invoked after each batch completes with results and progress
|
|
158
196
|
:param max_limit: Maximum batch size limit for the operation
|
|
159
197
|
:param args: Additional args for operation_func
|
|
160
198
|
:param kwargs: Additional kwargs for operation_func
|
|
@@ -163,9 +201,21 @@ async def process_with_retries(
|
|
|
163
201
|
# Initialize result array with None placeholders
|
|
164
202
|
max_index = max(r.original_index for r in records_with_attempts)
|
|
165
203
|
final_results: List[Optional[CollectionResult]] = [None] * (max_index + 1)
|
|
204
|
+
total_records_count = max_index + 1
|
|
205
|
+
|
|
206
|
+
# Initialize progress state
|
|
207
|
+
progress_state = {
|
|
208
|
+
"total_records": total_records_count,
|
|
209
|
+
"records_completed": 0,
|
|
210
|
+
"records_succeeded": 0,
|
|
211
|
+
"records_failed": 0,
|
|
212
|
+
"records_pending": total_records_count,
|
|
213
|
+
"current_attempt": 1,
|
|
214
|
+
"current_batch_size": 0,
|
|
215
|
+
"current_concurrency": 0,
|
|
216
|
+
}
|
|
166
217
|
|
|
167
218
|
current_records = records_with_attempts
|
|
168
|
-
total_retry_count = 0
|
|
169
219
|
|
|
170
220
|
while current_records:
|
|
171
221
|
current_attempt = current_records[0].attempt
|
|
@@ -176,6 +226,11 @@ async def process_with_retries(
|
|
|
176
226
|
current_attempt, max_concurrent_batches
|
|
177
227
|
)
|
|
178
228
|
|
|
229
|
+
# Update progress state for current attempt
|
|
230
|
+
progress_state["current_attempt"] = current_attempt
|
|
231
|
+
progress_state["current_batch_size"] = current_batch_size
|
|
232
|
+
progress_state["current_concurrency"] = current_concurrency
|
|
233
|
+
|
|
179
234
|
logger.debug(
|
|
180
235
|
f"Processing {len(current_records)} records on attempt {current_attempt} "
|
|
181
236
|
f"with batch_size={current_batch_size}, concurrency={current_concurrency}"
|
|
@@ -185,23 +240,15 @@ async def process_with_retries(
|
|
|
185
240
|
records_to_process = [r.record for r in current_records]
|
|
186
241
|
batches = split_into_batches(records_to_process, current_batch_size, max_limit)
|
|
187
242
|
|
|
188
|
-
#
|
|
189
|
-
wrapped_callback = None
|
|
190
|
-
if on_batch_complete:
|
|
191
|
-
|
|
192
|
-
async def progress_wrapper(progress: ProgressInfo):
|
|
193
|
-
progress["retry_count"] = total_retry_count
|
|
194
|
-
await on_batch_complete(progress)
|
|
195
|
-
|
|
196
|
-
wrapped_callback = progress_wrapper
|
|
197
|
-
|
|
198
|
-
# Process batches with current concurrency level
|
|
243
|
+
# Process batches - callback will be invoked for each batch with results
|
|
199
244
|
batch_results = await process_batches_concurrently(
|
|
200
245
|
batches,
|
|
201
246
|
operation_func,
|
|
202
247
|
current_concurrency,
|
|
203
248
|
len(records_to_process),
|
|
204
|
-
|
|
249
|
+
on_result,
|
|
250
|
+
progress_state,
|
|
251
|
+
final_results,
|
|
205
252
|
*args,
|
|
206
253
|
**kwargs,
|
|
207
254
|
)
|
|
@@ -215,12 +262,24 @@ async def process_with_retries(
|
|
|
215
262
|
final_results,
|
|
216
263
|
)
|
|
217
264
|
|
|
265
|
+
# Update progress state based on results for next iteration
|
|
266
|
+
records_succeeded = sum(
|
|
267
|
+
1 for r in final_results if r is not None and r.get("success", False)
|
|
268
|
+
)
|
|
269
|
+
records_failed = sum(
|
|
270
|
+
1 for r in final_results if r is not None and not r.get("success", False)
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
progress_state["records_completed"] = records_succeeded + records_failed
|
|
274
|
+
progress_state["records_succeeded"] = records_succeeded
|
|
275
|
+
progress_state["records_failed"] = records_failed
|
|
276
|
+
progress_state["records_pending"] = len(records_to_retry)
|
|
277
|
+
|
|
218
278
|
if records_to_retry:
|
|
219
279
|
logger.info(
|
|
220
280
|
f"Retrying {len(records_to_retry)} failed records "
|
|
221
281
|
f"(attempt {records_to_retry[0].attempt})"
|
|
222
282
|
)
|
|
223
|
-
total_retry_count += len(records_to_retry)
|
|
224
283
|
|
|
225
284
|
current_records = records_to_retry
|
|
226
285
|
|
aio_sf/api/collections/client.py
CHANGED
|
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from ..client import SalesforceClient
|
|
10
10
|
|
|
11
|
-
from .batch import
|
|
11
|
+
from .batch import ResultCallback, process_with_retries
|
|
12
12
|
from .records import (
|
|
13
13
|
detect_record_type_and_sobject,
|
|
14
14
|
prepare_records,
|
|
@@ -92,7 +92,7 @@ class CollectionsAPI:
|
|
|
92
92
|
batch_size: Union[int, List[int]] = 200,
|
|
93
93
|
max_concurrent_batches: Union[int, List[int]] = 5,
|
|
94
94
|
api_version: Optional[str] = None,
|
|
95
|
-
|
|
95
|
+
on_result: Optional[ResultCallback] = None,
|
|
96
96
|
max_attempts: int = 1,
|
|
97
97
|
should_retry: Optional[ShouldRetryCallback] = None,
|
|
98
98
|
) -> CollectionInsertResponse:
|
|
@@ -109,7 +109,7 @@ class CollectionsAPI:
|
|
|
109
109
|
:param batch_size: Batch size (int for same size, or list of ints per attempt). Max 200.
|
|
110
110
|
:param max_concurrent_batches: Maximum number of concurrent batch operations
|
|
111
111
|
:param api_version: API version to use
|
|
112
|
-
:param
|
|
112
|
+
:param on_result: Optional async callback invoked after each batch completes with results
|
|
113
113
|
:param max_attempts: Maximum number of attempts per record (default: 1, no retries)
|
|
114
114
|
:param should_retry: Optional callback to determine if a failed record should be retried
|
|
115
115
|
:returns: List of results for each record, in same order as input
|
|
@@ -139,7 +139,7 @@ class CollectionsAPI:
|
|
|
139
139
|
max_attempts,
|
|
140
140
|
should_retry,
|
|
141
141
|
max_concurrent_batches,
|
|
142
|
-
|
|
142
|
+
on_result,
|
|
143
143
|
self.MAX_RECORDS_INSERT,
|
|
144
144
|
actual_sobject_type,
|
|
145
145
|
all_or_none,
|
|
@@ -200,7 +200,7 @@ class CollectionsAPI:
|
|
|
200
200
|
batch_size: Union[int, List[int]] = 200,
|
|
201
201
|
max_concurrent_batches: Union[int, List[int]] = 5,
|
|
202
202
|
api_version: Optional[str] = None,
|
|
203
|
-
|
|
203
|
+
on_result: Optional[ResultCallback] = None,
|
|
204
204
|
max_attempts: int = 1,
|
|
205
205
|
should_retry: Optional[ShouldRetryCallback] = None,
|
|
206
206
|
) -> CollectionUpdateResponse:
|
|
@@ -217,7 +217,7 @@ class CollectionsAPI:
|
|
|
217
217
|
:param batch_size: Batch size (int for same size, or list of ints per attempt). Max 200.
|
|
218
218
|
:param max_concurrent_batches: Maximum number of concurrent batch operations
|
|
219
219
|
:param api_version: API version to use
|
|
220
|
-
:param
|
|
220
|
+
:param on_result: Optional async callback invoked after each batch completes with results
|
|
221
221
|
:param max_attempts: Maximum number of attempts per record (default: 1, no retries)
|
|
222
222
|
:param should_retry: Optional callback to determine if a failed record should be retried
|
|
223
223
|
:returns: List of results for each record, in same order as input
|
|
@@ -247,7 +247,7 @@ class CollectionsAPI:
|
|
|
247
247
|
max_attempts,
|
|
248
248
|
should_retry,
|
|
249
249
|
max_concurrent_batches,
|
|
250
|
-
|
|
250
|
+
on_result,
|
|
251
251
|
self.MAX_RECORDS_UPDATE,
|
|
252
252
|
actual_sobject_type,
|
|
253
253
|
all_or_none,
|
|
@@ -313,7 +313,7 @@ class CollectionsAPI:
|
|
|
313
313
|
batch_size: Union[int, List[int]] = 200,
|
|
314
314
|
max_concurrent_batches: Union[int, List[int]] = 5,
|
|
315
315
|
api_version: Optional[str] = None,
|
|
316
|
-
|
|
316
|
+
on_result: Optional[ResultCallback] = None,
|
|
317
317
|
max_attempts: int = 1,
|
|
318
318
|
should_retry: Optional[ShouldRetryCallback] = None,
|
|
319
319
|
) -> CollectionUpsertResponse:
|
|
@@ -331,7 +331,7 @@ class CollectionsAPI:
|
|
|
331
331
|
:param batch_size: Batch size (int for same size, or list of ints per attempt). Max 200.
|
|
332
332
|
:param max_concurrent_batches: Maximum number of concurrent batch operations
|
|
333
333
|
:param api_version: API version to use
|
|
334
|
-
:param
|
|
334
|
+
:param on_result: Optional async callback invoked after each batch completes with results
|
|
335
335
|
:param max_attempts: Maximum number of attempts per record (default: 1, no retries)
|
|
336
336
|
:param should_retry: Optional callback to determine if a failed record should be retried
|
|
337
337
|
:returns: List of results for each record, in same order as input
|
|
@@ -361,7 +361,7 @@ class CollectionsAPI:
|
|
|
361
361
|
max_attempts,
|
|
362
362
|
should_retry,
|
|
363
363
|
max_concurrent_batches,
|
|
364
|
-
|
|
364
|
+
on_result,
|
|
365
365
|
self.MAX_RECORDS_UPSERT,
|
|
366
366
|
external_id_field,
|
|
367
367
|
actual_sobject_type,
|
|
@@ -411,7 +411,7 @@ class CollectionsAPI:
|
|
|
411
411
|
batch_size: Union[int, List[int]] = 200,
|
|
412
412
|
max_concurrent_batches: Union[int, List[int]] = 5,
|
|
413
413
|
api_version: Optional[str] = None,
|
|
414
|
-
|
|
414
|
+
on_result: Optional[ResultCallback] = None,
|
|
415
415
|
max_attempts: int = 1,
|
|
416
416
|
should_retry: Optional[ShouldRetryCallback] = None,
|
|
417
417
|
) -> CollectionDeleteResponse:
|
|
@@ -427,7 +427,7 @@ class CollectionsAPI:
|
|
|
427
427
|
:param batch_size: Batch size (int for same size, or list of ints per attempt). Max 200.
|
|
428
428
|
:param max_concurrent_batches: Maximum number of concurrent batch operations
|
|
429
429
|
:param api_version: API version to use
|
|
430
|
-
:param
|
|
430
|
+
:param on_result: Optional async callback invoked after each batch completes with results
|
|
431
431
|
:param max_attempts: Maximum number of attempts per record (default: 1, no retries)
|
|
432
432
|
:param should_retry: Optional callback to determine if a failed record should be retried
|
|
433
433
|
:returns: List of results for each record, in same order as input
|
|
@@ -453,7 +453,7 @@ class CollectionsAPI:
|
|
|
453
453
|
max_attempts,
|
|
454
454
|
should_retry,
|
|
455
455
|
max_concurrent_batches,
|
|
456
|
-
|
|
456
|
+
on_result,
|
|
457
457
|
self.MAX_RECORDS_DELETE,
|
|
458
458
|
all_or_none,
|
|
459
459
|
api_version,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aio-sf
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0b10
|
|
4
4
|
Summary: Async Salesforce library for Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/callawaycloud/aio-salesforce
|
|
6
6
|
Project-URL: Repository, https://github.com/callawaycloud/aio-salesforce
|
|
@@ -153,24 +153,44 @@ asyncio.run(main())
|
|
|
153
153
|
|
|
154
154
|
### Collections API - Batch Operations
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
Bulk operations (insert, update, upsert, delete) with automatic batching and concurrency.
|
|
157
157
|
|
|
158
|
+
**Basic Usage:**
|
|
158
159
|
```python
|
|
159
160
|
async with SalesforceClient(auth_strategy=auth) as sf:
|
|
160
161
|
records = [{"Name": f"Account {i}"} for i in range(1000)]
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
results = await sf.collections.insert(
|
|
164
|
-
records, sobject_type="Account",
|
|
165
|
-
batch_size=200, max_concurrent_batches=5
|
|
166
|
-
)
|
|
167
|
-
|
|
163
|
+
results = await sf.collections.insert(records, sobject_type="Account")
|
|
168
164
|
# Also: update(), upsert(), delete()
|
|
169
165
|
```
|
|
170
166
|
|
|
171
|
-
**
|
|
167
|
+
**Advanced - With Retries, Concurrency Scaling, and Progress:**
|
|
168
|
+
```python
|
|
169
|
+
from aio_sf.api.collections import ResultInfo
|
|
170
|
+
|
|
171
|
+
async def on_result(info: ResultInfo):
|
|
172
|
+
# Called after each batch completes with successes and errors split
|
|
173
|
+
print(
|
|
174
|
+
f"Batch: {len(info['successes'])} succeeded, {len(info['errors'])} failed | "
|
|
175
|
+
f"Attempt {info['current_attempt']}, "
|
|
176
|
+
f"Overall: {info['records_succeeded']} OK, {info['records_failed']} failed, "
|
|
177
|
+
f"{info['records_pending']} pending"
|
|
178
|
+
)
|
|
179
|
+
# Inspect errors (includes both API errors and HTTP failures)
|
|
180
|
+
for error in info['errors']:
|
|
181
|
+
print(f" Error: {error['errors']}")
|
|
182
|
+
|
|
183
|
+
async with SalesforceClient(auth_strategy=auth) as sf:
|
|
184
|
+
results = await sf.collections.insert(
|
|
185
|
+
records=records,
|
|
186
|
+
sobject_type="Account",
|
|
187
|
+
batch_size=[200, 100, 25], # Shrink batch size on retry
|
|
188
|
+
max_concurrent_batches=[5, 3, 1], # Reduce concurrency on retry
|
|
189
|
+
max_attempts=5, # Retry up to 5 times
|
|
190
|
+
on_result=on_result, # Callback with results
|
|
191
|
+
)
|
|
192
|
+
```
|
|
172
193
|
|
|
173
|
-
See [RETRY_GUIDE.md](RETRY_GUIDE.md) for advanced retry strategies, progress tracking, and custom error handling.
|
|
174
194
|
|
|
175
195
|
## Exporter
|
|
176
196
|
|
|
@@ -11,9 +11,9 @@ aio_sf/api/auth/static_token.py,sha256=xAXpLkzRh6hDEiaKeR9N3Tk-0PuAAZKKU9Ivs0W81
|
|
|
11
11
|
aio_sf/api/bulk_v2/__init__.py,sha256=TxNM9dFmRX5k57Wj_JnposeEqqd9xcJx78wI-d6VH0o,315
|
|
12
12
|
aio_sf/api/bulk_v2/client.py,sha256=t2vl8bIIvSrbg5T1mFDm7O4vq0GyDihfkVHamGYnZ7I,6817
|
|
13
13
|
aio_sf/api/bulk_v2/types.py,sha256=18TN_VMisKJVCvo39q36moYXQhGLRUs73CKWIxBeAcs,1471
|
|
14
|
-
aio_sf/api/collections/__init__.py,sha256=
|
|
15
|
-
aio_sf/api/collections/batch.py,sha256=
|
|
16
|
-
aio_sf/api/collections/client.py,sha256=
|
|
14
|
+
aio_sf/api/collections/__init__.py,sha256=Loy9PVf7VsFqs9J2s5n6DO1txy6H5xdHU422CnuMkaM,677
|
|
15
|
+
aio_sf/api/collections/batch.py,sha256=mRhWBNIvSfgw9tk9PP1DzUmgTdEwB-bThKN8195luH8,14755
|
|
16
|
+
aio_sf/api/collections/client.py,sha256=gR1z3Q5K6iZvcYzJJ6n0azoEdNYp7UdefHMV8jb2RZY,19044
|
|
17
17
|
aio_sf/api/collections/records.py,sha256=UwI4mjoMkJPBCYbsNUmj5HTBjbGdcaMHT6UiJ4EmcUA,5371
|
|
18
18
|
aio_sf/api/collections/retry.py,sha256=RXTpMhWyeYsXNiojgEYIVnGtg8S0iYMxgfWgX3APahE,4669
|
|
19
19
|
aio_sf/api/collections/types.py,sha256=vWjVVySjV8eRFgdGHiP8QiyaZZ5PtxMl0PyFEZ6yNtY,762
|
|
@@ -26,7 +26,7 @@ aio_sf/api/query/types.py,sha256=Wfk75kJpNDCGpTHonCbzjWvayy8guA3eyZp3hE7nBt0,845
|
|
|
26
26
|
aio_sf/exporter/__init__.py,sha256=waTegrvw_SvJzREAWD4twSDldSL-HfvhLTLLT1o765o,771
|
|
27
27
|
aio_sf/exporter/bulk_export.py,sha256=2GtiwXChf7dq7dByGLPDhIJJg-yq9eyoE57H4Ekqaus,13169
|
|
28
28
|
aio_sf/exporter/parquet_writer.py,sha256=jGiLooxyaqciSDUbXj5F_4uWoR_YrQaB-PrDfRuXR3Y,14495
|
|
29
|
-
aio_sf-0.1.
|
|
30
|
-
aio_sf-0.1.
|
|
31
|
-
aio_sf-0.1.
|
|
32
|
-
aio_sf-0.1.
|
|
29
|
+
aio_sf-0.1.0b10.dist-info/METADATA,sha256=jC8DcA0rPFavqImBvSZhqfWNGwVEboglPqmhbXu_J9Y,8282
|
|
30
|
+
aio_sf-0.1.0b10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
31
|
+
aio_sf-0.1.0b10.dist-info/licenses/LICENSE,sha256=gu0Cbpiqs-vX7YgJJhGI1jH1mHup3dZMrZc-gmpEG60,1071
|
|
32
|
+
aio_sf-0.1.0b10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|