d-markey / squadron

Multithreading and worker thread pool for Dart / Flutter, to offload CPU-bound and heavy I/O tasks to Isolate or Web Worker threads.
https://pub.dev/packages/squadron
MIT License
80 stars 0 forks source link

[wasm] TypeError #40

Open sabin26 opened 2 weeks ago

sabin26 commented 2 weeks ago
import 'package:squadron/squadron.dart';

import 'codec_service.activator.g.dart';
import 'dart:convert';

part 'codec_service.worker.g.dart';

@SquadronService(baseUrl: '/services/codec')
class CodecService {
  CodecService();

  @SquadronMethod()
  Future<Map<String, Object?>> decode(final List<int> bytes) async =>
      const Utf8Decoder().fuse(const JsonDecoder()).convert(bytes) as Map<String, Object?>? ?? <String, Object?>{};
}

The same code works as expected when my flutter app is compiled to javascript but when I compile it to wasm, I get the following error:

$Error._throw   @   main.dart.wasm:0x3c1991
$_TypeError._throwAsCheckError  @   errors_patch.dart:74
$<obj> as Class(Object) @   main.dart.wasm:0x427d0b
$openChannel closure at file:///C:/Users/Dell/AppData/Local/Pub/Cache/git/squadron-fad409c841390c2ed1987d937d7d79c5a776c7f9/lib/src/_impl/web/_channel.dart:62:22   @   _channel.dart:68
$closure wrapper at file:///C:/Users/Dell/AppData/Local/Pub/Cache/git/squadron-fad409c841390c2ed1987d937d7d79c5a776c7f9/lib/src/_impl/web/_channel.dart:62:22 trampoline    @   main.dart.wasm:0x4e7a4b
$_1828  @   main.dart.wasm:0x3bf91e
(anonymous) @   main.dart.mjs:627
error       
_4694   @   main.dart.mjs:957
$Worker|set#onerror @   main.dart.wasm:0x4e7a5b
$openChannel inner  @   _channel.dart:62
$openChannel    @   _channel.dart:32
$Channel.open   @   channel.dart:69
$Worker.start inner @   worker.dart:244
$Worker.start   @   worker.dart:240
$WorkerPool._provisionWorkers   @   worker_pool.dart:152
$WorkerPool._schedule   @   worker_pool.dart:328
$WorkerPool._enqueue    @   worker_pool.dart:268
$WorkerPool.scheduleValueTask   @   worker_pool.dart:288
$WorkerPool.execute @   worker_pool.dart:276
$CodecServiceWorkerPool.decode  @   codec_service.worker.g.dart:54
$login inner    @   auth_provider.dart:166
$_awaitHelper closure at org-dartlang-sdk:///dart-sdk/lib/_internal/wasm/lib/async_patch.dart:83:16 @   async_patch.dart:84
$closure wrapper at org-dartlang-sdk:///dart-sdk/lib/_internal/wasm/lib/async_patch.dart:83:16 trampoline   @   main.dart.wasm:0xac05fe
$_rootRunUnary  @   zone.dart:1407
$_rootRunUnary tear-off trampoline  @   main.dart.wasm:0x4c85df
$_CustomZone.runUnary   @   zone.dart:1308
$_FutureListener.handleValue    @   future_impl.dart:163
$_Future._propagateToListeners closure handleValueCallback at org-dartlang-sdk:///dart-sdk/lib/async/future_impl.dart:859:33    @   future_impl.dart:861
$_Future._propagateToListeners  @   future_impl.dart:890
$_Future._completeWithValue @   future_impl.dart:666
$_Future._asyncCompleteWithValue closure at org-dartlang-sdk:///dart-sdk/lib/async/future_impl.dart:735:29  @   future_impl.dart:736
$closure wrapper at org-dartlang-sdk:///dart-sdk/lib/async/future_impl.dart:735:29 trampoline   @   main.dart.wasm:0x428529
$_rootRun   @   zone.dart:1399
$_rootRun tear-off trampoline   @   main.dart.wasm:0x4c8647
$_CustomZone.run    @   zone.dart:1301
$_CustomZone.runGuarded @   zone.dart:1209
$_CustomZone.bindCallbackGuarded closure at org-dartlang-sdk:///dart-sdk/lib/async/zone.dart:1249:12    @   zone.dart:1249
$closure wrapper at org-dartlang-sdk:///dart-sdk/lib/async/zone.dart:1249:12 trampoline @   main.dart.wasm:0x4c8769
$_microtaskLoop @   schedule_microtask.dart:40
$_startMicrotaskLoop    @   schedule_microtask.dart:49
$_startMicrotaskLoop tear-off trampoline    @   main.dart.wasm:0x41c69c
$_invokeCallback    @   internal_patch.dart:96
(anonymous) @   main.dart.mjs:647

Pubspec.yaml

dependencies:
  squadron:
    git:
      url: https://github.com/d-markey/squadron
      ref: main
dependency_overrides:
  squadron:
    git:
      url: https://github.com/d-markey/squadron
      ref: main
dev_dependencies:
  squadron_builder:
    git:
      url: https://github.com/d-markey/squadron_builder
      ref: main
d-markey commented 2 weeks ago

I've committed https://github.com/d-markey/squadron/commit/7e951e7a51fa189984a0c40862991746cb6f468e to tentatively fix your issue... according to the stack trace, it happens on line 68 in lib/src/_impl/web/_channel.dart, where something like $<obj> as Class(Object) is happening since err is dynamic. So it will probably uncover another issue and the connection will likely raise a SquadronErrorExt.create('Unexpected error').

Could you post the generated code from codec_service.worker.g.dart? (avoid posting the full code in a comment, just attach the file instead please)

d-markey commented 2 weeks ago

Also, I understand you compiled your Flutter app to Web Assembly, but did you also compile workers to Web Assembly?

d-markey commented 2 weeks ago

At least, this fix made test "- Squadron Worker - initialization error - not found" pass again :-) Thanks!

sabin26 commented 2 weeks ago

Also, I understand you compiled your Flutter app to Web Assembly, but did you also compile workers to Web Assembly?

Scenario 1: CodecService

@SquadronService(baseUrl: '/services/codec', wasm: false) // Raises runtime exception TypeError (this issue)
@SquadronService(baseUrl: '/services/codec', wasm: true) // No error but I would get on to scenario 2

Scenario 2: WebSocketService

@SquadronService(baseUrl: '/services/websocket', wasm: true) // Another issue but no exception

For wasm: false (default):

dart compile js codec_service.web.g.dart -o codec_service.web.g.dart.js

For wasm: true:

dart compile wasm codec_service.web.g.dart -o codec_service.web.g.dart.wasm

I don't know how to explain scenario 2 because there is no exception, but I don't receive WebSocket messages in a Stream. I will open another issue if this issue resolves first.

sabin26 commented 2 weeks ago

Flutter app does runtime check to see if the browser supports wasm. How will squadron manage to do the same ? For js app, load js worker and for wasm app, load wasm worker ?

Do I have to dual compile ?

dart compile js codec_service.web.g.dart -o codec_service.web.g.dart.js
dart compile wasm codec_service.web.g.dart -o codec_service.web.g.dart.wasm
sabin26 commented 2 weeks ago

Could you post the generated code from codec_service.worker.g.dart? (avoid posting the full code in a comment, just attach the file instead please)

I had to change the extension to .txt to upload it here.

codec_service.worker.g.txt

d-markey commented 2 weeks ago

Thanks for the file, I don't think the error comes from the generated code.

What output do you have in your browser's console logs?

sabin26 commented 2 weeks ago

The logs I shared on the first post is from the browser console when the app is launched and some action is performed. The app compiles to wasm sucessfully. So, no compilation error.

d-markey commented 2 weeks ago

Flutter app does runtime check to see if the browser supports wasm. How will squadron manage to do the same ? For js app, load js worker and for wasm app, load wasm worker ?

Do I have to dual compile ?

Yes, you'd have to dual compile AND implement any logic you need to serve JS or wasm. I believe you'd also have to copy the files generated by squadron_builder, because the entry point URI is either js or wasm. Also the worker code is hard-wired on that URI, so the generated worker code will also need some adaptations.

It's an interesting feature, I'll keep that in mind once everything wasm is sorted out.