Sometimes you just gotta stop and have a bump…

My headaches described below were due to my npm module’s dependency clauses’ versioning stanzas. I had set dependencies to automatically update but clipped them to the current minor version. Eventually they got crusty, and npm actually stopped finding the versions I was demanding in a speedy fashion. Both edges of the upgrade knife can cut you, don’t let dependencies get too old. 🙂 Fuller explanation on SO.

Historical blathering follows… (continued…)

This is a sweet spot of thread functionality for me at the moment, mixing boost and c++11, so I’m throwing it down here.  It’s also in my Reusable code on git.

// --------------------------------------------------------------------
// CONCISE EXAMPLE OF THREAD WITH EXTERNALLY-ACCESSIBLE STATUS AND DATA
// --------------------------------------------------------------------
// We create a vector, and create a thread to start stuffing it.
// Externally, we can check the status of the job, and have mutex access to the data.
// The atomic job stage is SO CHEAP to change and check, do it all day long as needed.
// Initially, externally, we check the job stage.
// Meanwhile, we do a bunch of intense work inside the mutex.
// Then we do smaller work with frequent mutexing, allowing interruption.
// Great patterns, use them brother!
// Hells to the yeah.
// --------------------------------------------------------------------
std::atomic<int32_t> job_stage(0);
std::unordered_set<int> data;
boost::shared_mutex data_guard;
data.insert(-1);
std::thread t([&job_stage,&data,&data_guard] {
    // stage 1 = jam in data
    job_stage = 1;
    {
        boost::upgrade_lock<boost::shared_mutex> lock(data_guard);
        boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
        for (int loop = 0; loop < 2000; ++loop)
        {
            std::this_thread::sleep_for(1ms);
            data.insert(loop);
        }
    }
    // stage 2 = mutex-jam data, allowing intervention
    job_stage = 2;
    for (int loop = 3000000; loop < 4000000 && job_stage == 2; ++loop)
    {
        boost::upgrade_lock<boost::shared_mutex> lock(data_guard);
        boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
        data.insert(loop);
    }
    cout << "thread exiting..." << endl;
});

cout << "pre mutex job stage: " << job_stage << endl;

for (int check = 0; check < 5; ++check)
{
    std::this_thread::sleep_for(200ms);
    // not sure why i was getting std::hex output...
    cout << "check " << check << " job stage: ";
    {
        boost::upgrade_lock<boost::shared_mutex> lock(data_guard);
        cout  << dec << job_stage << " data size " << data.size();
    }
    cout << endl;
}

// We can trigger the thread to exit.
job_stage = 3;

// Let's see what happens if we don't join until after the thread is done.
std::this_thread::sleep_for(300ms);
cout << "done sleeping" << endl;

// NOW we will block to ensure the thread finishes.
cout << "joining" << endl;
t.join();
cout << "all done" << endl;
// --------------------------------------------------------------------

Output:

pre mutex job stage: 1
check 0 job stage: 2 data size 2031
check 1 job stage: 2 data size 225848
check 2 job stage: 2 data size 456199
check 3 job stage: 2 data size 726576
check 4 job stage: 2 data size 936429
thread exiting...
check 5 job stage: 2 data size 1002001
done sleeping
joining
all done

Five minutes into this javascript exploit video, you’ll understand why that massive stack of node modules in your app is BAD.  Nicely done.

And… 14 minutes in and he hits Moment.js… which is everywhere… with a straightforward tough-to-solve regex DDOS hack.

Then mongoose… then…

Diamond dependencies are everywhere, from dll dependency hell to running an upgradable linux distro to your node stack to figuring out your #include order.  Check out Titus’s perspective, it’s pretty tight.