janmisek / ember-error-handler

Error handling for ambitious web applications
MIT License
4 stars 2 forks source link

Q: route consumer #5

Closed basz closed 5 years ago

basz commented 5 years ago

I'm wondering if the following scenario is the correct one.

I want my app to go to a maintenance page whenever our endpoints start returning 503's I've got this for ember-data and my own ajax calls.

However I'm also using ember-simple-auth to authenticate. When that fails I need to throw an exception like so:

 actions: {
    authenticate(identity, password) {
      this.get('session').authenticate('authenticator:oauth2-password-grant', identity, password)
        .catch(error => {
          if (!isNone(error.status) && 503 === error.status) {
            throw new MaintenanceError();
          }
    }
  }

However the trick from the ember pages does not work and the wsod is invoked.

app/routes/application.js

error(error, transition) {
      alert('error in app');
      if (error instanceof MaintenanceError) {
        this.transitionTo('under-maintenance');
        return;
      }

      // ...other error handling logic
    }

I'm guessing creating an consumer and somehow registering that would be able to do this. Is that guess correct and what step would I need to take to do that?

Thanks for an otherwise great add-on

janmisek commented 5 years ago

Yes this is correct approach.

Register your own consumer as first consumer and process errors yourself. See examples from my application:

# instance-initializers/ember-error-handler-instance-initializer.js

export default {
  after: 'ember-error-handler-instance-initializer',
  name: 'ember-error-handler-extensions-instance-initializer',
  initialize(owner) {
    const manager = owner.lookup('service:ember-error-handler.error-manager');

    // insert consumer on first position to skip ember concurrency errors
    manager.get('consumers').unshift(
      FilterErrorConsumer.create(owner.ownerInjection())
    );

    // push consumer to stop routing on error
    manager.get('consumers').push(
      RefreshOnErrorConsumer.create(owner.ownerInjection())
    )

  }
};

then implement your own consumer. Error is not processed further when false is returned from consumer.

# filter-error-consumer.js

export default BaseConsumer.extend({

  /**
   * we skip cancelled tasks errors in production
   * http://ember-concurrency.com/#/docs/task-cancelation-help
   *
   * @param e
   * @returns {boolean}
   */
  isCancelled(errorDescriptor) {

    let e = errorDescriptor.error;
    let cancelled = false;
    do {
      if (e) {
        cancelled = cancelled || didCancel(e);
        e = e.previous
      }
    } while (e);

    if (cancelled) {
      if (config.environment !== 'production') {
        const loggerService = getOwner(this).lookup(LOGGER_SERVICE_NAME);
        loggerService.warn('Supressed error: Ember concurrency task cancelled', errorDescriptor.get('normalizedStack'));
      }
      return true;
    }

  },

  consume(errorDescriptor) {

    if (this.isCancelled(errorDescriptor)) {
      return false;
    }

    // add other filters here

    return true;
  }

})
basz commented 5 years ago

Apart from LOGGER_SERVICE_NAME not being defined I got it working!

Great and thank you!