Skip to content

childprocess.spawn breaks process.context #1807

Description

@barocsi

Interestingly after calling an imagemagick function from a models remotemethod, after successful callback loopback.getCurrentContext() returns null.

Imagemagick spawns a child process and an event listener does the callback function call.

from imagemagick.js

 var Accumulator = function(cb) {
    this.stdout = {contents: ""};
    this.stderr = {contents: ""};
    this.callback = cb;
    var limitedWrite = function(stream) {
      return function(chunk) {
        stream.contents += chunk;
        if (!killed && stream.contents.length > options.maxBuffer) {
          child.kill(options.killSignal);
          killed = true;
        }
      };
    };
    this.out = limitedWrite(this.stdout);
    this.err = limitedWrite(this.stderr);
  };

Accumulator.prototype.finish = function(err) {
    this.callback(err, this.stdout.contents, this.stderr.contents); 
};

 child.addListener(version[0] == 0 && version[1] < 7 ? "exit" : "close", function (code, signal) {
    console.log("acccc")
    var loopback = require('loopback')
    console.log(loopback.getCurrentContext())
    if (timeoutId) clearTimeout(timeoutId);
    if (code === 0 && signal === null) {
      std.finish(null);
    } else {
      var e = new Error("Command "+(timedOut ? "timed out" : "failed")+": " + std.errCurrent());
      e.timedOut = timedOut;
      e.killed = killed;
      e.code = code;
      e.signal = signal;
      std.finish(e);
    }

where std.finish() simply does the callback

Well I am not sure where is this relates to the getCurrentContext, however in the loopback source there are corresponding lines from current-context.js

loopback.createContext = function(scopeName) {
    // Make the namespace globally visible via the process.context property
    process.context = process.context || {};
    var ns = process.context[scopeName];
    if (!ns) {
      ns = cls.createNamespace(scopeName);
      process.context[scopeName] = ns;
      // Set up loopback.getCurrentContext()
      loopback.getCurrentContext = function() {
        return ns && ns.active ? ns : null;
      };

      chain(juggler);
      chain(remoting);
    }
    return ns;
  };

It seems that loopback simply stores values in the process.context
And more interestingly BEFORE calling the child.spawn command we have a different context object after the child finishes and exits.

Before the call we have a process.context object like this:

{ loopback:
   Namespace {
     name: 'loopback',
     active: { accessToken: [Object], currentUser: [Object] },
     _set: [ null, [Object] ],
     id:
      AsyncListener {
        create: [Function],
        flags: 15,
        before: [Function],
        after: [Function],
        error: [Function],
        uid: 2,
        data: null } } }

but after the child process exits the process.context changes to:

{ loopback:
   Namespace {
     name: 'loopback',
     active: null,
     _set: [],
     id:
      AsyncListener {
        create: [Function],
        flags: 15,
        before: [Function],
        after: [Function],
        error: [Function],
        uid: 2,
        data: null } } }

Any ideas on what could break the context object?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions