Skip to content

Instantly share code, notes, and snippets.

@martletandco
Last active April 4, 2017 11:26
Show Gist options
  • Save martletandco/6e048dc11c174e38ebef5fd5b5819477 to your computer and use it in GitHub Desktop.
Save martletandco/6e048dc11c174e38ebef5fd5b5819477 to your computer and use it in GitHub Desktop.
ember-concurrency-batch-process
import Ember from 'ember';
import {task, timeout} from 'ember-concurrency';
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
arg: 1,
batchedArgs: Ember.A([]),
results: Ember.A([]),
processInTask: true,
processing: Ember.computed.or('processSoon.isRunning', 'processNow.isRunning'),
// entry point; enqueue the batched args, and "kick"
// the debounced restartable processSoon task
enqueueForProcessing(...args) {
this.get('batchedArgs').pushObject(args);
this.get('processSoon').perform();
},
processSoon: task(function * () {
yield timeout(700); // debounce
let batchedArgs = this.get('batchedArgs').toArray();
// this.get('batchedArgs').clear();
// pause to let slow human enqueue after queue is cleared
yield timeout(500);
this.get('batchedArgs').clear();
if(this.get('processInTask')) {
this.get('processNow').perform(batchedArgs);
return;
}
// this is the weird part; this processBatchNow is still
// part of the the restartable `processSoon` task, so if
// `enqueueForProcessing` for processing gets called and
// it kicks `processSoon`, it'll restart right in the middle
// of `processBatchNow`. And even if `processBatchNow()` were NOT
// restartable (because, say, it's just a function that returns
// an uncancelable promise), we'd still need to honor the
// constraint to not concurrently run `processBatchNow`.
let results = yield processBatchNow(batchedArgs);
this.get('results').pushObject(results.join(', '));
}).restartable(),
processNow: task(function * (batchedArgs) {
let results = yield processBatchNow(batchedArgs);
this.get('results').pushObject(results.join(', '));
}),
actions: {
enqueue(arg) {
this.enqueueForProcessing(arg);
this.incrementProperty('arg');
},
clear() {
this.get('results').clear();
},
},
});
function processBatchNow(args) {
let d = Ember.RSVP.defer();
setTimeout(() => {
let results = args.map(a => a * 2);
d.resolve(results);
}, 2000);
return d.promise;
}
<h1>EC batch processing</h1>
<p>Try enqueuing more items immediately after the queue is cleared. Notice that when 'batch via task' is checked, the results are contiguous, but unchecked there are missing numbers</p>
<dl>
<dt><label for="batch-via-task">batch via task</label></dt>
<dd>{{input type="checkbox" id="batch-via-task" name="batch-via-task" checked=processInTask}}</dd>
<dt>queue length</dt>
<dd>{{batchedArgs.length}}</dd>
<dt>processSoon task</dt>
<dd>{{if processSoon.isRunning 'running' 'idle'}}</dd>
{{#if processInTask}}
<dt>processNow task</dt>
<dd>
{{if processNow.isRunning 'running' 'idle'}}
{{#if processNow.isRunning}}x{{processNow.concurrency}} {{/if}}
</dd>
{{/if}}
</dl>
<button {{action 'enqueue' arg}}>Enqueue</button> {{if processing 'working...'}}
<h2>Results</h2>
<button {{action 'clear' arg}}>Clear</button>
<ul>
{{#each results as |result|}}
<li>{{result}}</li>
{{/each}}
</ul>
<br>
{
"version": "0.12.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.12.0",
"ember-template-compiler": "2.12.0",
"ember-testing": "2.12.0"
},
"addons": {
"ember-concurrency": "0.7.19"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment