Esempio n. 1
0
async def main():
    async with Golem(budget=1.0, subnet_tag="devnet-beta") as golem:
        cluster = await golem.run_service(DateService, num_instances=1)
        start_time = datetime.now()

        while datetime.now() < start_time + timedelta(minutes=1):
            for num, instance in enumerate(cluster.instances):
                print(
                    f"Instance {num} is {instance.state.value} on {instance.provider_name}"
                )
            await asyncio.sleep(REFRESH_INTERVAL_SEC)
Esempio n. 2
0
async def test_emit_event_class(dummy_yagna_engine):
    got_events_1 = []
    got_events_2 = []
    got_events_3 = []

    def event_consumer_1(event: events.Event):
        got_events_1.append(event)

    def event_consumer_2(event: events.Event):
        got_events_2.append(event)

    def event_consumer_3(event: events.Event):
        got_events_3.append(event)

    golem = Golem(budget=1, app_key="NOT_A_REAL_APPKEY")

    golem.add_event_consumer(event_consumer_1, [events.SubscriptionEvent])
    golem.add_event_consumer(event_consumer_2,
                             [events.TaskEvent, "ServiceEvent"])
    golem.add_event_consumer(event_consumer_3)
    async with golem:
        invoice_received = golem._engine.emit(events.InvoiceReceived,
                                              job="foo",
                                              agreement="bar",
                                              invoice="baz")
        subscription_created = golem._engine.emit(events.SubscriptionCreated,
                                                  job="foo",
                                                  subscription="bar")
        service_finished = golem._engine.emit(events.ServiceFinished,
                                              job="foo",
                                              agreement="bar",
                                              activity="baz",
                                              service="???")
        task_started = golem._engine.emit(events.TaskStarted,
                                          job="foo",
                                          agreement="bar",
                                          activity="baz",
                                          task="???")

    assert got_events_1 == [subscription_created]
    assert got_events_2 == [service_finished, task_started]

    #   Additional ShutdownFinished event is passed to the catchall consumer only
    assert got_events_3[:4] == [
        invoice_received,
        subscription_created,
        service_finished,
        task_started,
    ]
    assert len(got_events_3) == 5 and isinstance(got_events_3[4],
                                                 events.ShutdownFinished)
Esempio n. 3
0
async def main():
    package = await vm.repo(
        image_hash="d646d7b93083d817846c2ae5c62c72ca0507782385a2e29291a3d376",
    )

    tasks = [Task(data=None)]

    async with Golem(budget=1.0, subnet_tag="devnet-beta") as golem:
        async for completed in golem.execute_tasks(worker,
                                                   tasks,
                                                   payload=package):
            print(completed.result.stdout)
Esempio n. 4
0
async def main():

    vm_package = await vm.repo(
        image_hash="9a3b5d67b0b27746283cb5f287c13eab1beaa12d92a9f536b747c7ae",
        min_mem_gib=0.5,
        min_storage_gib=2.0,
    )

    async def worker(work_ctx, tasks):
        async for task in tasks:
            script = work_ctx.new_script()
            print("task data:", task.data, file=sys.stderr)
            script.run("/bin/sleep", "1")
            yield script
            task.accept_result(result=task.data)

    async with Golem(
            budget=10.0,
            subnet_tag="goth",
            event_consumer=log_event_repr,
    ) as golem:

        # We use an async task generator that yields tasks removed from
        # an async queue. Each computed task will potentially spawn
        # new tasks -- this is made possible thanks to using async task
        # generator as an input to `executor.submit()`.

        task_queue = asyncio.Queue()

        # Seed the queue with the first task:
        await task_queue.put(Task(data=3))

        async def input_generator():
            """Task generator yields tasks removed from `queue`."""
            while True:
                task = await task_queue.get()
                if task.data == 0:
                    break
                yield task

        async for task in golem.execute_tasks(
                worker,
                input_generator(),
                vm_package,
                max_workers=1,
                timeout=timedelta(minutes=6),
        ):
            print("task result:", task.result, file=sys.stderr)
            for n in range(task.result):
                await task_queue.put(Task(data=task.result - 1))

        print("all done!", file=sys.stderr)
Esempio n. 5
0
async def test_emit_event(dummy_yagna_engine):
    got_events_1 = []
    got_events_2 = []
    got_events_3 = []
    got_events_4 = []

    def event_consumer_1(event: events.Event) -> None:
        #   Event consumer passed to Golem()
        got_events_1.append(event)

    def event_consumer_2(event: events.Event) -> None:
        #   Event consumer passed via add_event_consumer to not-yet-started Golem
        got_events_2.append(event)

    def event_consumer_3(event: events.Event) -> None:
        #   Event consumer passed to working Golem
        got_events_3.append(event)

    golem = Golem(budget=1,
                  event_consumer=event_consumer_1,
                  app_key="NOT_A_REAL_APPKEY")
    golem.add_event_consumer(event_consumer_2)
    async with golem:
        golem.add_event_consumer(event_consumer_3)
        for sample_event in sample_events:
            event_class, event_kwargs = type(sample_event), asdict(
                sample_event)
            del event_kwargs["timestamp"]  # timestamp is set only internally
            emitted_event = golem._engine.emit(event_class, **event_kwargs)
            got_events_4.append(emitted_event)
    assert got_events_1 == emitted_events
    assert got_events_2 == emitted_events
    assert got_events_3 == emitted_events
    assert got_events_4 == sample_events

    #   When exiting from golem contextmanager, new `_Engine` is created -> we must ensure
    #   event consumers are not lost when `_Engine` exits -> so we repeat the same test again
    got_events_1.clear()
    got_events_2.clear()
    got_events_3.clear()
    got_events_4.clear()
    async with golem:
        for sample_event in sample_events:
            event_class, event_kwargs = type(sample_event), asdict(
                sample_event)
            del event_kwargs["timestamp"]  # timestamp is set only internally
            emitted_event = golem._engine.emit(event_class, **event_kwargs)
            got_events_4.append(emitted_event)
    assert got_events_1 == emitted_events
    assert got_events_2 == emitted_events
    assert got_events_3 == emitted_events
    assert got_events_4 == sample_events
Esempio n. 6
0
async def main():

    async with Golem(budget=1.0, subnet_tag="goth") as golem:

        # Start a cluster with a single service.
        # The first instance will fail before reaching the `running` state
        # due to an error. Another instance should be spawned in its place.

        log("Starting cluster...")
        await golem.run_service(FirstInstanceFailsToStart)

        # This another instance should get to `running` state.

        while not instances_running:
            log("Waiting for an instance...")
            await asyncio.sleep(2)

        # And then stop.

        while not instances_stopped:
            log("Waiting until the instance stops...")
            await asyncio.sleep(2)

        # Then we start another cluster with a single instance.
        # This time the instance is stopped by a signal before it reaches the `running` state,
        # but in that case the cluster should not spawn another instance.

        log("Starting another cluster...")
        cluster = await golem.run_service(FirstInstanceFailsToStart)

        while instances_started < 3:
            log("Waiting for another instance...")
            await asyncio.sleep(2)

        assert [i for i in cluster.instances if i.is_available]

        log("Closing the second cluster...")
        cluster.stop()

        while [i for i in cluster.instances if i.is_available]:
            log("Waiting for the cluster to stop...")
            await asyncio.sleep(2)

        log("Cluster stopped")
async def main(running_time_sec, subnet_tag, driver=None, network=None):

    # necessary to set maximum price for one unit of custom counter,
    # default strategy does not take custom counter prices into account
    strategy = LeastExpensiveLinearPayuMS(
        max_price_for={
            com.Counter.CPU.value: Decimal("0.2"),
            com.Counter.TIME.value: Decimal("0.1"),
            "golem.usage.custom.counter": Decimal("0.1"),
        })

    async with Golem(
            budget=10.0,
            subnet_tag=subnet_tag,
            payment_driver=driver,
            payment_network=network,
            strategy=strategy,
    ) as golem:
        instance_params = [{"running_time_sec": running_time_sec}]
        cluster = await golem.run_service(CustomCounterService,
                                          instance_params=instance_params)

        def print_instances():
            print(
                f"instances: {[{s.id, s.state.value} for s in cluster.instances]}"
            )

        was_running = False

        while True:
            await asyncio.sleep(3)

            if was_running and all([
                    s.state == ServiceState.terminated
                    for s in cluster.instances
            ]):
                print_instances()
                print("All services were successfully terminated")
                break

            if len(cluster.instances) > 0:
                print_instances()
                was_running = True
Esempio n. 8
0
async def main():
    package = await vm.repo(
        image_hash="d646d7b93083d817846c2ae5c62c72ca0507782385a2e29291a3d376")

    tasks = [Task(data=None)]
    timeout = timedelta(hours=24)

    async with Golem(
            budget=10.0,
            strategy=ShortDebitNoteIntervalAndPaymentTimeout(),
            subnet_tag="goth",
            event_consumer=log_event_repr,
    ) as golem:
        logger = logging.getLogger("yapapi")
        logger.handlers[0].setLevel(logging.DEBUG)
        async for completed in golem.execute_tasks(worker,
                                                   tasks,
                                                   payload=package,
                                                   max_workers=1,
                                                   timeout=timeout):
            print(f"Task finished: {completed}.")
Esempio n. 9
0
async def main(subnet_tag,
               payment_driver=None,
               payment_network=None,
               num_instances=2):
    # By passing `event_consumer=log_summary()` we enable summary logging.
    # See the documentation of the `yapapi.log` module on how to set
    # the level of detail and format of the logged information.
    async with Golem(
            budget=1.0,
            subnet_tag=subnet_tag,
            payment_driver=payment_driver,
            payment_network=payment_network,
    ) as golem:
        print_env_info(golem)

        network = await golem.create_network("192.168.0.1/24")
        async with network:
            cluster = await golem.run_service(SshService,
                                              network=network,
                                              num_instances=num_instances)
            instances = cluster.instances

            while True:
                print(instances)
                try:
                    await asyncio.sleep(5)
                except (KeyboardInterrupt, asyncio.CancelledError):
                    break

            cluster.stop()

            cnt = 0
            while cnt < 3 and any(s.is_available for s in instances):
                print(instances)
                await asyncio.sleep(5)
                cnt += 1
Esempio n. 10
0
async def main(subnet_tag, payment_driver=None, payment_network=None):
    package = await vm.repo(
        image_hash="a23ce2c0c29ea9711e4a293a2805700e2f0cb6450fddf9506812eb1b",
        min_mem_gib=0.5,
        min_storage_gib=2.0,
    )
    tasks = [() for _ in range(10)]

    async def worker(ctx: WorkContext, tasks):
        async for task in tasks:
            output_file = f"output_{datetime.now()}_{random.random()}.txt"
            script = ctx.new_script(timeout=timedelta(minutes=10))
            script.run("/usr/bin/stress-ng", "--cpu", "1", "--timeout", "1")
            script.run("/golem/task.sh", "-o", "1024", "-t", "5")
            script.run("/golem/task.sh", "-f",
                       "/golem/output/output.txt,1048576")
            script.download_file(f"/golem/output/output.txt", output_file)
            script.run("/golem/task.sh", "-e", "1024", "-t", "5")

            try:
                yield script
                task.accept_result(result=output_file)
            except BatchTimeoutError:
                print(
                    f"{TEXT_COLOR_RED}"
                    f"Task {task} timed out on {ctx.provider_name}, time: {task.running_time}"
                    f"{TEXT_COLOR_DEFAULT}")
                raise

    async with Golem(
            budget=10.0,
            subnet_tag=subnet_tag,
            payment_driver=payment_driver,
            payment_network=payment_network,
    ) as golem:

        print(
            f"yapapi version: {TEXT_COLOR_YELLOW}{yapapi_version}{TEXT_COLOR_DEFAULT}\n"
            f"Using subnet: {TEXT_COLOR_YELLOW}{subnet_tag}{TEXT_COLOR_DEFAULT}, "
            f"payment driver: {TEXT_COLOR_YELLOW}{golem.payment_driver}{TEXT_COLOR_DEFAULT}, "
            f"and network: {TEXT_COLOR_YELLOW}{golem.payment_network}{TEXT_COLOR_DEFAULT}\n"
        )

        num_tasks = 0
        start_time = datetime.now()

        completed_tasks = golem.execute_tasks(
            worker,
            [Task(data=data) for data in tasks],
            payload=package,
            max_workers=50,
            timeout=timedelta(minutes=30),
        )
        async for task in completed_tasks:
            num_tasks += 1
            print(
                f"{TEXT_COLOR_CYAN}"
                f"Task computed: {task}, result: {task.result}, time: {task.running_time}"
                f"{TEXT_COLOR_DEFAULT}")

        print(
            f"{TEXT_COLOR_CYAN}"
            f"{num_tasks} tasks computed, total time: {datetime.now() - start_time}"
            f"{TEXT_COLOR_DEFAULT}")
Esempio n. 11
0

if __name__ == "__main__":
    parser = build_parser("Render a Blender scene")
    parser.add_argument("--show-usage", action="store_true", help="show activity usage and cost")
    parser.add_argument(
        "--min-cpu-threads",
        type=int,
        default=2,
        help="require the provider nodes to have at least this number of available CPU threads",
    )
    now = datetime.now().strftime("%Y-%m-%d_%H.%M.%S")
    parser.set_defaults(log_file=f"blender-yapapi-{now}.log")
    args = parser.parse_args()

    golem = Golem(
        budget=10,
        subnet_tag=args.subnet_tag,
        payment_driver=args.payment_driver,
        payment_network=args.payment_network,
    )

    run_golem_example(
        main(
            golem,
            show_usage=args.show_usage,
            min_cpu_threads=args.min_cpu_threads,
        ),
        log_file=args.log_file,
    )
Esempio n. 12
0
async def main(subnet_tag, payment_driver, payment_network, port):
    async with Golem(
            budget=1.0,
            subnet_tag=subnet_tag,
            payment_driver=payment_driver,
            payment_network=payment_network,
    ) as golem:
        print_env_info(golem)

        network = await golem.create_network("192.168.0.1/24")
        async with network:
            db_cluster = await golem.run_service(DbService, network=network)
            db_instance = db_cluster.instances[0]

            def still_starting(cluster):
                return any(i.state in (ServiceState.pending,
                                       ServiceState.starting)
                           for i in cluster.instances)

            def raise_exception_if_still_starting(cluster):
                if still_starting(cluster):
                    raise Exception(
                        f"Failed to start {cluster} instances "
                        f"after {STARTING_TIMEOUT.total_seconds()} seconds")

            commissioning_time = datetime.now()

            while (still_starting(db_cluster)
                   and datetime.now() < commissioning_time + STARTING_TIMEOUT):
                print(db_cluster.instances)
                await asyncio.sleep(5)

            raise_exception_if_still_starting(db_cluster)

            print(
                f"{TEXT_COLOR_CYAN}DB instance started, spawning the web server{TEXT_COLOR_DEFAULT}"
            )

            web_cluster = await golem.run_service(
                HttpService,
                network=network,
                instance_params=[{
                    "db_address": db_instance.network_node.ip
                }],
            )

            # wait until all remote http instances are started

            while (still_starting(web_cluster)
                   and datetime.now() < commissioning_time + STARTING_TIMEOUT):
                print(web_cluster.instances + db_cluster.instances)
                await asyncio.sleep(5)

            raise_exception_if_still_starting(web_cluster)

            # service instances started, start the local HTTP server

            proxy = LocalHttpProxy(web_cluster, port)
            await proxy.run()

            print(
                f"{TEXT_COLOR_CYAN}Local HTTP server listening on:\nhttp://localhost:{port}{TEXT_COLOR_DEFAULT}"
            )

            # wait until Ctrl-C

            while True:
                print(web_cluster.instances + db_cluster.instances)
                try:
                    await asyncio.sleep(10)
                except (KeyboardInterrupt, asyncio.CancelledError):
                    break

            # perform the shutdown of the local http server and the service cluster

            await proxy.stop()
            print(f"{TEXT_COLOR_CYAN}HTTP server stopped{TEXT_COLOR_DEFAULT}")

            web_cluster.stop()
            db_cluster.stop()

            cnt = 0
            while cnt < 3 and any(
                    s.is_available
                    for s in web_cluster.instances + db_cluster.instances):
                print(web_cluster.instances + db_cluster.instances)
                await asyncio.sleep(5)
                cnt += 1
Esempio n. 13
0
async def main(args):
    package = await vm.repo(
        image_hash="055911c811e56da4d75ffc928361a78ed13077933ffa8320fb1ec2db",
        min_mem_gib=0.5,
        min_storage_gib=2.0,
    )

    async with Golem(
        budget=10.0,
        subnet_tag=args.subnet_tag,
        payment_driver=args.payment_driver,
        payment_network=args.payment_network,
    ) as golem:
        print_env_info(golem)

        start_time = datetime.now()

        completed = golem.execute_tasks(
            compute_keyspace,
            [Task(data="compute_keyspace")],
            payload=package,
            timeout=KEYSPACE_TIMEOUT_ALL_TASKS,
        )

        keyspace = 0
        async for task in completed:
            keyspace = task.result

        print(
            f"{TEXT_COLOR_CYAN}"
            f"Task computed: keyspace size count. The keyspace size is {keyspace}"
            f"{TEXT_COLOR_DEFAULT}"
        )

        data = (Task(data=c) for c in range(0, keyspace, args.chunk_size))
        max_workers = args.max_workers or math.ceil(keyspace / args.chunk_size) // 2

        completed = golem.execute_tasks(
            perform_mask_attack,
            data,
            payload=package,
            max_workers=max_workers,
            timeout=MASK_ATTACK_TIMEOUT,
        )

        password = None

        async for task in completed:
            print(
                f"{TEXT_COLOR_CYAN}Task computed: {task}, result: {task.result}{TEXT_COLOR_DEFAULT}"
            )

            result = _parse_result(task.result)
            if result:
                password = result

        if password:
            print(f"{TEXT_COLOR_GREEN}Password found: {password}{TEXT_COLOR_DEFAULT}")
        else:
            print(f"{TEXT_COLOR_RED}No password found{TEXT_COLOR_DEFAULT}")

        print(f"{TEXT_COLOR_CYAN}Total time: {datetime.now() - start_time}{TEXT_COLOR_DEFAULT}")
Esempio n. 14
0
async def main(subnet_tag, payment_driver, payment_network, num_instances, port, running_time):
    async with Golem(
        budget=1.0,
        subnet_tag=subnet_tag,
        payment_driver=payment_driver,
        payment_network=payment_network,
    ) as golem:
        print_env_info(golem)

        commissioning_time = datetime.now()

        network = await golem.create_network("192.168.0.1/24")
        cluster = await golem.run_service(
            HttpService,
            network=network,
            num_instances=num_instances,
            expiration=datetime.now(timezone.utc)
            + STARTING_TIMEOUT
            + EXPIRATION_MARGIN
            + timedelta(seconds=running_time),
        )
        instances = cluster.instances

        def still_starting():
            return any(i.state in (ServiceState.pending, ServiceState.starting) for i in instances)

        # wait until all remote http instances are started

        while still_starting() and datetime.now() < commissioning_time + STARTING_TIMEOUT:
            print(f"instances: {instances}")
            await asyncio.sleep(5)

        if still_starting():
            raise Exception(
                f"Failed to start instances after {STARTING_TIMEOUT.total_seconds()} seconds"
            )

        # service instances started, start the local HTTP server

        proxy = LocalHttpProxy(cluster, port)
        await proxy.run()

        print(
            f"{TEXT_COLOR_CYAN}Local HTTP server listening on:\nhttp://localhost:{port}{TEXT_COLOR_DEFAULT}"
        )

        # wait until Ctrl-C

        start_time = datetime.now()

        while datetime.now() < start_time + timedelta(seconds=running_time):
            print(instances)
            try:
                await asyncio.sleep(10)
            except (KeyboardInterrupt, asyncio.CancelledError):
                break

        # perform the shutdown of the local http server and the service cluster

        await proxy.stop()
        print(f"{TEXT_COLOR_CYAN}HTTP server stopped{TEXT_COLOR_DEFAULT}")

        cluster.stop()

        cnt = 0
        while cnt < 3 and any(s.is_available for s in instances):
            print(instances)
            await asyncio.sleep(5)
            cnt += 1

        await network.remove()
Esempio n. 15
0
async def test_incorrect_event_class_str():
    golem = Golem(budget=1, app_key="NOT_A_REAL_APPKEY")
    with pytest.raises(ValueError):
        golem.add_event_consumer(lambda event: event, ["NoSuchEvent"])
Esempio n. 16
0
async def main():

    vm_package = await vm.repo(
        image_hash="9a3b5d67b0b27746283cb5f287c13eab1beaa12d92a9f536b747c7ae",
        min_mem_gib=0.5,
        min_storage_gib=2.0,
    )

    first_task = True

    async def duplicator(work_ctx, tasks):
        """A worker that executes `echo {task.data} {task.data}` command on provider.

        The command's output is the result of the whole task.

        The first ever task computed by an instance of this worker fails.
        It succeeds when re-tried. This may be used to test re-trying tasks,
        creating new agreements and displaying summary information on task/activity
        failures.
        """
        async for task in tasks:

            nonlocal first_task

            script = work_ctx.new_script()

            if first_task:
                first_task = False
                script.run("/bin/sleep", "1")
                script.run("/command/not/found")

            script.run("/bin/sleep", "1")
            future_result = script.run("/bin/echo", task.data, task.data)
            yield script
            result = await future_result
            output = result.stdout.strip()
            task.accept_result(output)

    async with Golem(budget=1.0, subnet_tag="goth") as golem:

        # Construct a pipeline:
        #
        #   input_tasks
        #        |
        #        V
        #    [ Job ALEF ]
        #        |
        #        V
        # intermediate_tasks
        #        |
        #        V
        #    [ Job BET ]
        #        |
        #        V
        #   output_tasks

        input_tasks = [Task(s) for s in "01234567"]

        computed_input_tasks = golem.execute_tasks(
            duplicator,
            input_tasks,
            payload=vm_package,
            max_workers=1,
            job_id="ALEF",
        )

        async def intermediate_tasks():
            async for task in computed_input_tasks:
                print(f"ALEF computed task: {task.data} -> {task.result}", file=sys.stderr)
                yield Task(data=task.result)

        output_tasks = golem.execute_tasks(
            duplicator,
            intermediate_tasks(),
            payload=vm_package,
            max_workers=1,
            job_id="BET",
        )

        async for task in output_tasks:
            print(f"BET computed task: {task.data} -> {task.result}", file=sys.stderr)
Esempio n. 17
0
async def main(
    subnet_tag,
    running_time,
    payment_driver=None,
    payment_network=None,
    num_instances=1,
    show_usage=False,
):
    async with Golem(
        budget=1.0,
        subnet_tag=subnet_tag,
        payment_driver=payment_driver,
        payment_network=payment_network,
    ) as golem:
        print_env_info(golem)

        commissioning_time = datetime.now()

        # start the service

        cluster = await golem.run_service(
            SimpleService,
            instance_params=[
                {"instance_name": f"simple-service-{i+1}", "show_usage": show_usage}
                for i in range(num_instances)
            ],
            expiration=datetime.now(timezone.utc)
            + STARTING_TIMEOUT
            + EXPIRATION_MARGIN
            + timedelta(seconds=running_time),
        )

        print(f"{TEXT_COLOR_YELLOW}" f"Starting {cluster}..." f"{TEXT_COLOR_DEFAULT}")

        def print_instances():
            print(
                f"instances: "
                + str(
                    [
                        f"{s.name}: {s.state.value}"
                        + (f" on {s.provider_name}" if s.provider_id else "")
                        for s in cluster.instances
                    ]
                )
            )

        def still_starting():
            return any(
                i.state in (ServiceState.pending, ServiceState.starting) for i in cluster.instances
            )

        # wait until instances are started

        while still_starting() and datetime.now() < commissioning_time + STARTING_TIMEOUT:
            print_instances()
            await asyncio.sleep(5)

        if still_starting():
            raise Exception(f"Failed to start instances before {STARTING_TIMEOUT} elapsed :( ...")

        print(f"{TEXT_COLOR_YELLOW}All instances started :){TEXT_COLOR_DEFAULT}")

        # allow the service to run for a short while
        # (and allowing its requestor-end handlers to interact with it)

        start_time = datetime.now()

        while datetime.now() < start_time + timedelta(seconds=running_time):
            print_instances()
            await asyncio.sleep(5)

        print(f"{TEXT_COLOR_YELLOW}Stopping {cluster}...{TEXT_COLOR_DEFAULT}")
        cluster.stop()

        # wait for instances to stop

        cnt = 0
        while cnt < 10 and any(s.is_available for s in cluster.instances):
            print_instances()
            await asyncio.sleep(5)

    print_instances()
Esempio n. 18
0
async def test_demand_resubscription(log_dir: Path, goth_config_path: Path,
                                     monkeypatch) -> None:
    """Test that checks that a demand is re-submitted after its previous submission expires."""

    configure_logging(log_dir)

    # Override the default test configuration to create only one provider node
    nodes = [
        {
            "name": "requestor",
            "type": "Requestor"
        },
        {
            "name": "provider-1",
            "type": "VM-Wasm-Provider",
            "use-proxy": True
        },
    ]
    goth_config = load_yaml(goth_config_path, [("nodes", nodes)])

    vm_package = await vm.repo(
        image_hash="9a3b5d67b0b27746283cb5f287c13eab1beaa12d92a9f536b747c7ae",
        min_mem_gib=0.5,
        min_storage_gib=2.0,
    )

    runner = Runner(base_log_dir=log_dir,
                    compose_config=goth_config.compose_config)

    async with runner(goth_config.containers):

        requestor = runner.get_probes(probe_type=RequestorProbe)[0]
        env = dict(os.environ)
        env.update(requestor.get_agent_env_vars())

        # Setup the environment for the requestor
        for key, val in env.items():
            monkeypatch.setenv(key, val)

        monitor = EventMonitor()
        monitor.add_assertion(assert_demand_resubscribed)
        monitor.start()

        # The requestor

        enable_default_logger()

        async def worker(work_ctx, tasks):
            async for task in tasks:
                script = work_ctx.new_script()
                script.run("/bin/sleep", "5")
                yield script
                task.accept_result()

        async with Golem(
                budget=10.0,
                event_consumer=monitor.add_event_sync,
        ) as golem:

            task: Task  # mypy needs this for some reason
            async for task in golem.execute_tasks(
                    worker,
                [Task(data=n) for n in range(20)],
                    vm_package,
                    max_workers=1,
                    timeout=timedelta(seconds=30),
            ):
                logger.info("Task %d computed", task.data)

        await monitor.stop()
        for a in monitor.failed:
            raise a.result()