run in worker thread