-
Notifications
You must be signed in to change notification settings - Fork 13
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
feat: add import bulk/resume
commands
#1091
Conversation
`data import bulk` will cache the API used when it created the job
isState: true, | ||
filename: BulkImportRequestCache.getFileName(), | ||
stateFolder: Global.SF_STATE_FOLDER, | ||
ttl: Duration.days(7), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bulk ingest/query job results are available for 7 days after being created:
https://developer.salesforce.com/docs/atlas.en-us.252.0.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_bulkapi.htm
jobId: string; | ||
processedRecords?: number; | ||
successfulRecords?: number; | ||
failedRecords?: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSON output:
async: jobID
sync: jobID and num of processed/successful/failed records
}); | ||
|
||
try { | ||
await job.poll(5000, timeout.milliseconds); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5s for the polling interval, we could add a --poll-interval
flag if users want to customize this later.
jobId: jobInfo.id, | ||
processedRecords: jobInfo.numberRecordsProcessed, | ||
successfulRecords: jobInfo.numberRecordsProcessed - (jobInfo.numberRecordsFailed ?? 0), | ||
failedRecords: jobInfo.numberRecordsFailed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API only gives us the total of records processed (that includes success/failure) and failed ones so we need calculate successful qty.
https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/get_job_info.htm
ms.stop('failed'); | ||
throw messages.createError( | ||
'error.jobFailed', | ||
[jobInfo.errorMessage, conn.getUsername(), job.id], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
jobInfo.errorMessage
is guaranteed to be present on state=Failed
:
https://github.com/jsforce/jsforce/blob/160426335c3d6f8efd1c3244eacb0454e755c988/src/api/bulk2.ts#L802
https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/get_job_info.htm
if (jobInfo.state === 'Aborted') { | ||
ms.stop('failed'); | ||
// TODO: replace this msg to point to `sf data bulk results` when it's added (W-12408034) | ||
throw messages.createError('error.jobAborted', [conn.getUsername(), job.id], [], err as Error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aborted jobs don't include an error msg, we log the sf org open ..
msg so they can view more details in the org.
char: 'w', | ||
unit: 'minutes', | ||
summary: messages.getMessage('flags.wait.summary'), | ||
defaultValue: 5, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data import resume
has a default wait time of 5 minutes.
This is on purpose so that if you don't specify --wait
you still have a good chance the job finishes on time.
data upsert resume
and data delete resume
have --wait
with 0
as a default, so on a first run without --wait
you have to re-run them again with a bigger timeout if the job is still running.
char: 'i', | ||
length: 18, | ||
startsWith: '750', | ||
exactlyOne: ['use-most-recent'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
following @VivekMChawla's comments about specificity:
https://salesforce-internal.slack.com/archives/G02K6C90RBJ/p1722277847033949
sf data import resume
is invalid, you have to pass either --job-id
or --use-most-recent
src/commands/data/import/resume.ts
Outdated
flags['job-id'], | ||
flags['use-most-recent'], | ||
undefined, | ||
undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the 4th arg is supposed to be api-version
but I didn't add that flag here because the API version used when creating the job is cached by data import bulk
so we don't need to pass it here.
src/commands/data/import/resume.ts
Outdated
const numberRecordsFailed = data?.numberRecordsFailed ?? 0; | ||
|
||
if (data?.numberRecordsProcessed) { | ||
return (data.numberRecordsProcessed - numberRecordsFailed).toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we default to 0
on L84 for failed records if no API info is available yet (this state update happens while job is being processed) but only render the Successful records
block if the API returns numberRecordsProcessed
.
This makes oclif/mso render a spinner instead of 0
when there's no processed data (first seconds of a job run or if it failed).
src/commands/data/import/resume.ts
Outdated
const jobInfo = await job.check(); | ||
|
||
// send last data update so job status/num. of records processed/failed represent the last update | ||
ms.goto('Processing the job', jobInfo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if job.poll
on L138 throws then the state rendered is from the previous poll update so we do one last update with fresh data from the org (job.check()
) so the last state rendered is accurate (job state, record counter).
QA 🔴 bulk import with --wait
It works as expected but 🟡 bulk import Question: is it supposed to be async by default?
🟢 bulk import with --async
🟢 resume an async import with --job-id
🟢 resume an async import with --use-most-recent
🟡 use invalid id for resume I would have expected an error about the id not being valid but instead got this. Not sure if that's right or not
🔴 links in terminal that doesn't support links you need to provide your own fallback so that terminal-link doesn't insert non-visible whitespace characters, which is what I think causes this issue. See https://github.com/salesforcecli/plugin-deploy-retrieve/blob/main/src/utils/deployStages.ts#L78 🟢 async insert and resume with large csv
🟢 handles failures
|
should be fixed now (
yes, same as
fixed by writing a separate cache resolver for
added the fallback |
@mdonnalley this is ready for review/qa again, thanks! also, please squash-merge the PR when it's good to go (bunch of commits in my branch) EDIT: |
`job.poll` is in a try/catch, when a failure happens it throws but also emits `error`. We avoid stopping MSO on `error` because we want to send a last update in the `catch` block
🟢 bulk import with --wait
🟢 use invalid id for resume
🟢 links in terminal that doesn't support links |
What does this PR do?
Adds 2 new commands:
data import bulk
take a CSV with fields of an object and bulk insert them into the org:
happy path
Screen.Recording.2024-10-16.at.10.57.01.AM.mov
failed to import all records
Screen.Recording.2024-10-16.at.11.07.10.AM.mov
job failure
job aborted
Screen.Recording.2024-10-16.at.11.12.26.AM.mov
data import resume
resume an async/timed out import
Screen.Recording.2024-10-16.at.11.17.31.AM.mov
testing instructions
checkout PR locally and
sf plugins link
it, you can use the following CSV files available in plugin-data for testing:test/test-files/data-project/data/bulkUpsertLarge.csv
(big)test/test-files/data-project/data/bulkUpsert.csv
(smol)What issues does this PR fix or reference?
@W-13656292@