   [type out colls sigs t0 & [opts]]
   (go (>! out (execution-result type colls sigs t0 opts))))
 
+(defn sync-signal-vertices
+  [vertices thresh]
+  (loop [sigs 0, verts vertices]
+    (if verts
+      (let [v (first verts)]
+        (if (should-signal? v thresh)
+          (do (debug (:id v) "signaling")
+              (signal! v sync-vertex-signal)
+              (recur (inc sigs) (next verts)))
+          (recur sigs (next verts))))
+      sigs)))
+
+(defn sync-collect-vertices
+  [vertices thresh]
+  (loop [colls 0, verts vertices]
+    (if verts
+      (let [v (first verts)]
+        (if (should-collect? v thresh)
+          (do (debug (:id v) "collecting")
+              (collect! v)
+              (recur (inc colls) (next verts)))
+          (recur colls (next verts))))
+      colls)))
+
+(defn parallel-sync-signal-vertices
+  [vertices thresh]
+  (r/fold
+   +
+   (fn
+     ([] 0)
+     ([acc v] (if (should-signal? v thresh) (do (signal! v sync-vertex-signal) (inc acc)) acc)))
+   vertices))
+
+(defn parallel-sync-collect-vertices
+  [vertices thresh]
+  (r/fold
+   +
+   (fn
+     ([] 0)
+     ([acc v] (if (should-collect? v thresh) (do (collect! v) (inc acc)) acc)))
+   vertices))
+
+(def default-sync-context-opts
+  {:collect-thresh 0
+   :signal-thresh  0
+   :max-iter       1e6
+   :signal-fn      sync-signal-vertices
+   :collect-fn     sync-collect-vertices})
+
+(defn sync-execution-context
+  [opts]
+  (let [ctx       (merge default-sync-context-opts opts)
+        g         (:graph ctx)
+        c-thresh  (:collect-thresh ctx)
+        s-thresh  (:signal-thresh ctx)
+        coll-fn   (:collect-fn ctx)
+        sig-fn    (:signal-fn ctx)
+        max-iter  (:max-iter ctx)
+        watch-id  (keyword (gensym))]
+    (reify
+      #?@(:clj
+           [clojure.lang.IDeref
+            (deref [_] ctx)]
+           :cljs
+           [IDeref
+            (-deref [_] ctx)])
+      IGraphExecutor
+      (stop! [_] (err/unsupported!))
+      (notify! [_ evt] (err/unsupported!))
+      (include-vertex! [_ v] (err/unsupported!))
+      (execute!
+        [_]
+        (add-watch! g :remove-vertex watch-id (fn [evt] (signal! (peek evt) sync-vertex-signal)))
+        (let [t0 (now)]
+          (loop [i 0, colls 0, sigs 0]
+            (if (<= i max-iter)
+              (let [verts (vertices g)
+                    sigs' (sig-fn verts s-thresh)
+                    colls' (coll-fn verts c-thresh)]
+                (if (and (pos? sigs') (pos? colls'))
+                  (recur (inc i) (long (+ colls colls')) (long (+ sigs sigs')))
+                  (do (remove-watch! g :remove-vertex watch-id)
+                      (execution-result :converged colls sigs t0 {:iterations i}))))
+              (do (remove-watch! g :remove-vertex watch-id)
+                  (execution-result :max-iter-reached colls sigs t0 {:iterations i})))))))))
+
 (defn stop-async-execution
   [bus vertices]
   (info "stopping execution context...")

      IGraphExecutor
      (stop!
        [_]
        (stop-async-execution bus (vertices (:graph ctx)))
        result)
      (notify! [_ evt]
        (go (>! (rand-nth bus) evt)))
      (include-vertex!
        [_ v]
        (processor v _)
        (when (should-collect? v c-thresh)
          (collect! v))
        (when (should-signal? v s-thresh)
          (signal! v async-vertex-signal))
        _)
      (execute!
        [_]
        (let [t0 (now)]
          (go
            (run! #(include-vertex! _ %) (vertices (:graph ctx)))
            (loop [colls 0, sigs 0]
              (if (<= (+ colls sigs) max-ops)
                (let [t (if max-t (timeout max-t))

    [_] (-> @state :vertices vals))
  (add-edge!
    [_ src dest sig-fn opts]
    (connect-to! src dest sig-fn opts)
    (notify-watches @watches [:add-edge src dest sig-fn opts])
    _)
  IWatchable
  (add-watch!
    [_ type id f]
    (info "adding watch" type id f)
    (swap! watches assoc-in [type id] f)
    _)
  (remove-watch!
    [_ type id]
    (info "removing watch" type id)
    (swap! watches update type dissoc id)
    _))

(defn compute-graph
  [] (InMemoryGraph. (atom {:vertices {} :next-id 0}) (atom {})))

#_(defn logged-compute-graph
    ([log-chan] (LoggedGraph. (compute-graph) log-chan))
    ([g log-chan] (LoggedGraph. g log-chan)))

(defn eager-async-vertex-processor
  [{:keys [id] :as vertex} ctx]
