1- import { initialize } from "./cluster.js"
21import { getMongoConnection , getPostgresConnection } from './db.js'
32import cliProgress from 'cli-progress'
4- import { setTimeout } from 'node:timers/promises'
3+ import Tasklets from '@wendelmax/tasklets'
4+ import path from 'node:path'
5+
6+ // Configure Tasklets worker pool
7+ const tasklets = new Tasklets ( )
8+ tasklets . configure ( {
9+ maxWorkers : 8 ,
10+ minWorkers : 8 ,
11+ idleTimeout : 30000 ,
12+ workload : 'io' ,
13+ adaptive : true ,
14+ } )
15+
16+ // Worker module path (CJS module loaded via require() inside worker threads)
17+ const INSERT_WORKER = `MODULE:${ path . join ( import . meta. dirname , 'insert-worker.cjs' ) } `
18+
19+ // Connect to databases
520const mongoDB = await getMongoConnection ( )
621const postgresDB = await getPostgresConnection ( )
22+
723const ITEMS_PER_PAGE = 4000
8- const CLUSTER_SIZE = 99
9- const TASK_FILE = new URL ( './background-task.js' , import . meta. url ) . pathname
1024
11- // console.log(`there was ${await postgresDB.students.count()} items on Postgres, deleting all...`)
25+ // Clean Postgres before migration
1226await postgresDB . students . deleteAll ( )
1327
28+ // Async generator to paginate through MongoDB
1429async function * getAllPagedData ( itemsPerPage , page = 0 ) {
15-
1630 const data = mongoDB . students . find ( ) . skip ( page ) . limit ( itemsPerPage )
1731 const items = await data . toArray ( )
1832 if ( ! items . length ) return
@@ -23,39 +37,38 @@ async function* getAllPagedData(itemsPerPage, page = 0) {
2337}
2438
2539const total = await mongoDB . students . countDocuments ( )
26- // console.log(`total items on DB: ${total}`)
2740
41+ // Progress bar
2842const progress = new cliProgress . SingleBar ( {
2943 format : 'progress [{bar}] {percentage}% | {value}/{total} | {duration}s' ,
3044 clearOnComplete : false ,
31- } , cliProgress . Presets . shades_classic ) ;
32-
33- progress . start ( total , 0 ) ;
34- let totalProcessed = 0
35- const cp = initialize (
36- {
37- backgroundTaskFile : TASK_FILE ,
38- clusterSize : CLUSTER_SIZE ,
39- amountToBeProcessed : total ,
40- async onMessage ( message ) {
41- progress . increment ( )
42-
43- if ( ++ totalProcessed !== total ) return
44- // console.log(`all ${amountToBeProcessed} processed! Exiting...`)
45- progress . stop ( )
46- cp . killAll ( )
47-
48- const insertedOnSQLite = await postgresDB . students . count ( )
49- console . log ( `total on MongoDB ${ total } and total on PostGres ${ insertedOnSQLite } ` )
50- console . log ( `are the same? ${ total === insertedOnSQLite ? 'yes' : 'no' } ` )
51- process . exit ( )
52-
53- }
54- }
55- )
56- await setTimeout ( 1000 )
57-
58- for await ( const data of getAllPagedData ( ITEMS_PER_PAGE ) ) {
59- cp . sendToChild ( data )
45+ } , cliProgress . Presets . shades_classic )
46+
47+ progress . start ( total , 0 )
48+
49+ // Process all pages in parallel using tasklets
50+ const promises = [ ]
51+
52+ for await ( const items of getAllPagedData ( ITEMS_PER_PAGE ) ) {
53+ // Convert MongoDB docs to plain objects (strip ObjectId etc.)
54+ const plainItems = items . map ( ( { name, email, age, registeredAt } ) => ( { name, email, age, registeredAt } ) )
55+
56+ const promise = tasklets . run ( INSERT_WORKER , plainItems ) . then ( count => {
57+ progress . increment ( count )
58+ } )
59+ promises . push ( promise )
6060}
6161
62+ await Promise . all ( promises )
63+
64+ progress . stop ( )
65+
66+ const insertedOnPostgres = await postgresDB . students . count ( )
67+ console . log ( `total on MongoDB ${ total } and total on PostGres ${ insertedOnPostgres } ` )
68+ console . log ( `are the same? ${ total === insertedOnPostgres ? 'yes' : 'no' } ` )
69+
70+ // Cleanup
71+ await mongoDB . client . close ( )
72+ await postgresDB . client . end ( )
73+ await tasklets . terminate ( )
74+ process . exit ( )
0 commit comments