CSV User List Import
Overview
Customers who already hold a list of LINE User IDs — for example when migrating off a legacy platform — can upload a CSV file to create the corresponding line_user rows.
This is a long-running job that validates each entry, fetches its profile from LINE, records a per-row result, summarises the statistics, and archives the detail records to S3 once finished.
Because the job runs for a long time and can fail partway through, it is protected on three fronts: up to two retries, a Redis processing lock, and a re-process path for imports left in limbo.
Business Flow
- Receive a
LineUserImportCSVUserPayloadcontainingimportId,lineOaId, andorganizationId. - Set the Redis flag
LINE_USER:<REDIS_KEY_IMPORT_CSV_USER_PROCESSING>:<importId>to prevent concurrent processing of the same import. - Load the
importrow from the database and read the CSV file from S3 viaGetFileContent. validateDelimiterconfirms the file uses the expected separator, thenparseLineUserIDsextracts the ID list.- Process one entry at a time in
processOneImportUser:- Validate the format against
^U[a-f0-9]{32}$; failures are recorded as invalid with a reason. - Check for an existing
line_userviacheckLineUserExists; a match counts as a duplicate. - For genuinely new users, fetch the profile from LINE with
getLineUserProfileand write the result intoimport_detail.
- Validate the format against
- Work through the list in batches of 100, writing progress back to the
importrow viaupdateImport. saveLineUserAccountcreates the realline_userrows from the validatedimport_detailrecords.updateImportSummarytotals up the counts: total, success, failed, and duplicate.emitAttributeChangeBatchpublishes the newly created users onto theattribute_changequeue so the trigger engine can evaluate rules against them.archiveImportDetailexports allimport_detailrows to a file and uploads it to S3 underprivate/<lineOaHash>/line-user-archive/, keeping the table size manageable over time.- On failure the job retries up to twice (
maxRetries) before marking the import as failed.ReProcessImportCSVUserexists to sweep up imports stuck in the pending state.
Key Files & Functions
internal/lineuser/import_service.go— the core of this feature, roughly 1,000 linesImportService.ProcessImportCSVUser(ctx, payload)— entry pointprocessOneImportUser(),getLineUserProfile(),parseLineUserIDs(),validateDelimiter()checkLineUserExists(),createImportDetails(),saveLineUserAccount()updateImport(),updateImportSummary(),emitAttributeChangeBatch()archiveImportDetail(),getImportDetails(),ReProcessImportCSVUser()- Key constants:
maxRetriesis 2,batchSizeis 100, plusfolderLineUserArchive
internal/lineuser/consumer.go—Consumer.HandleImportCSVUsercmd/worker/integration.go—lineUserStorage, the s3x adapter- Queues: consumes
line_import_csv_user, publishes toattribute_change(runtime profilemain)
Connections to Other Services
- Job source — cms-api-go (import domain), when a user uploads a file and starts the import.
- Database —
import(status and statistics),import_detail(per-row results),line_user(the rows actually created), andline_oa. - S3 — reads the source CSV and writes the archive file to
private/<lineOaHash>/line-user-archive/. - Redis — the key
LINE_USER:IMPORT_CSV_USER_PROCESSING:<importId>, whose prefix is configurable throughREDIS_KEY_IMPORT_CSV_USER_PROCESSING. - LINE API —
GET /v2/bot/profile/{userId}. - RabbitMQ — publishes onward to
attribute_change, consumed by the trigger engine. - Contrast with the import mapping job — this job creates new users, whereas import mapping enriches users that already exist.