Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide a thread safe context api like py-mini-racer #100

Closed
almahdi404 opened this issue Feb 24, 2024 · 8 comments
Closed

Provide a thread safe context api like py-mini-racer #100

almahdi404 opened this issue Feb 24, 2024 · 8 comments
Assignees
Labels
enhancement New feature or request question Further information is requested

Comments

@almahdi404
Copy link

almahdi404 commented Feb 24, 2024

In some cases the with api doesn't work. You need to store the context in an object.

import STPyV8
class Renderer:
    def __init__(self):
        self.ctx = STPyV8.JSContext()

The py-mini-racer context class(https://github.com/sqreen/PyMiniRacer/blob/f7b9da0d4987ca7d1982af7f24da423f06da9894/py_mini_racer/py_mini_racer.py#L163).

@almahdi404 almahdi404 changed the title Proivide a thread safe context api like py-mini-racer Provide a thread safe context api like py-mini-racer Feb 24, 2024
@buffer buffer self-assigned this Apr 16, 2024
@buffer
Copy link
Collaborator

buffer commented Apr 16, 2024

Can you please describe a scenario where this happens? Moreover providing some samples would be great so that I could take a look at them. Thanks!

@almahdi404
Copy link
Author

almahdi404 commented Apr 17, 2024

Thanks for showing interest!

I was trying to use it for SSR in a framework that i built called picomet.

In this(https://github.com/picomet/picomet/blob/main/src/picomet/transformer.py) file you can see how the MiniRacer context class is being used.

@buffer buffer added the enhancement New feature or request label May 16, 2024
@buffer
Copy link
Collaborator

buffer commented May 28, 2024

Sorry but I still can not understand the issue. If you need to use the JSContext instance multiple times you should really instantiate and use it every time you need it. Be aware that when you use the with statement, the JSContext is created and entered. When you're done the JSContext is exited and destroyed. So the following code

with STPyV8.JSContext() as ctx:
    ctx.eval()

does not preserve the created JSContext instance. If you need to do that just use the following code

# Store the JSContext in the object
self.ctx = STPyV8.JSContext()

# Reuse JScontext every time you need (the with statement cleanly and safely enters and exits it)
with self.ctx as ctx:
    ctx.eval()

Hope it helps!

@buffer buffer added the question Further information is requested label May 28, 2024
@almahdi404
Copy link
Author

Thanks. 😅

# Store the JSContext in the object
self.ctx = STPyV8.JSContext()

# Reuse JScontext every time you need (the with statement cleanly and safely enters and exits it)
with self.ctx as ctx:
    ctx.eval()

This is what I needed. Now I can persist data and retrieve them later when I need.

But unfortunately it's not thread safe currently. Can it be made thread safe?

@buffer
Copy link
Collaborator

buffer commented May 29, 2024

Have you already taken a look at https://github.com/cloudflare/stpyv8/blob/master/tests/test_Thread.py? Let me know if that helps.

@almahdi404
Copy link
Author

This doesn't work. I don't know if i am doing something wrong. Or maybe it's not possible.

import threading
import STPyV8
import time


class Global:
    count = 0
    started = threading.Event()
    finished = threading.Semaphore(0)

    def sleep(self, ms):
        time.sleep(ms / 1000.0)

        self.count += 1


g = Global()


def run():
    class Transformer:
        def __init__(self, *args, **kwargs):
            with STPyV8.JSIsolate():
                self.ctx = STPyV8.JSContext(g)

        def store(self):
            with STPyV8.JSIsolate():
                with self.ctx as ctx:
                    ctx.eval(
                        """
                            v = "hello world";
                        """
                    )

        def print(self):
            with STPyV8.JSIsolate():
                with self.ctx as ctx:
                    print(ctx.eval("v"))

    transformer = Transformer()
    transformer.store()
    transformer.print()


t = threading.Thread(target=run)
t.start()

@buffer
Copy link
Collaborator

buffer commented May 30, 2024

Seems like you are using different isolates for each operation and that's not correct. Please give this code a try. This should help you figure out how to proceed.

import threading
import STPyV8


class Global:
    result = []

    def add(self, value):
        with STPyV8.JSUnlocker():
            self.result.append(value)


class Transformer:
    def __init__(self):
        self.isolate = STPyV8.JSIsolate()
        self.isolate.enter()
        self.ctxt = STPyV8.JSContext(Global())

    def store(self):
        with self.ctxt:
            self.ctxt.eval(
                """
                    add(1234);
                """
            )

    def print(self):
        with self.ctxt:
            print(self.ctxt.eval("result"))


def run():
    transformer = Transformer()
    transformer.store()
    transformer.print()


t = threading.Thread(target=run)

with STPyV8.JSLocker():
    t.start()

@almahdi404
Copy link
Author

That worked 🙂. Thanks for the help and the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants