profile
viewpoint
Nathan Van Gheem vangheem Raleigh, NC https://nathanvangheem.com Software engineer and contrarian: - Python, AsyncIO - Guillotina/Plone - Pyramid, Django, other - JS: React, Angular - Microservices, cloud orchestrators

smcmahon/Products.PloneFormGen 32

PloneFormGen add on for Plone

onna/aiofluent 4

A structured logger for Fluentd (Python)

vangheem/collective.ptg.galleriffic 2

galleriffic ptg integration

vangheem/Bumblebee 1

deliverance-like implementation that only works on html output(no theme file)

vangheem/collective.bumblebee 1

Bumblebee integration with plone

espenmn/collective.ptg.contactsheep 0

A collective.ptg.contactsheet clone

push eventplone/guillotina

vangheem

commit sha 65ef1da85b4c4252dcc5bc61457ef7db0f095686

try again to fix retries

view details

push time in a minute

push eventplone/guillotina

vangheem

commit sha cad67c6cde9f34d84858c1d036dbb0e21168da7d

fix test

view details

push time in 9 minutes

created tagplone/guillotina

tag5.3.53

Python AsyncIO data API to manage billions of resources

created time in 2 hours

push eventplone/guillotina

vangheem

commit sha d80eabf851ac0673142695992b20db7bf890e811

Preparing release 5.3.53

view details

vangheem

commit sha ca290284723f146d728507d345b397ae122d0595

Back to development: 5.3.54

view details

push time in 2 hours

delete branch plone/guillotina

delete branch : in-memory-metrics

delete time in 2 hours

push eventplone/guillotina

Nathan Van Gheem

commit sha 8229442080d29a3a30fbbe65a262970ee251ec25

Add metrics for in-memory cache (#1014)

view details

push time in 2 hours

PR merged plone/guillotina

Reviewers
Add metrics for in-memory cache
+121 -11

2 comments

5 changed files

vangheem

pr closed time in 2 hours

Pull request review commentplone/guillotina

memcached objects cache driver

+from typing import List

maybe we should contribute to emcache to provide types?

lferran

comment created time in 2 hours

Pull request review commentplone/guillotina

memcached objects cache driver

 async def delete(self, key: str):     async def delete_all(self, keys: List[str]):         if self._pool is None:             raise NoRedisConfigured()-        for key in keys:-            try:-                with watch("delete_many"):++        with watch("delete_many"):+            for key in keys:+                try:                     await self._pool.execute(b"DEL", key)

metric here too then.

lferran

comment created time in 3 hours

Pull request review commentplone/guillotina

memcached objects cache driver

+try:+    import emcache+except ImportError:+    print("If you add guillotina.contrib.memcached you need to add emcache on your requirements")+    raise++from guillotina import app_settings+from guillotina import metrics+from guillotina.contrib.memcached.exceptions import NoMemcachedConfigured+from typing import Any+from typing import Dict+from typing import List+from typing import Optional++import asyncio+import backoff+import logging+++try:+    import prometheus_client++    MEMCACHED_OPS = prometheus_client.Counter(+        "guillotina_cache_memcached_ops_total",+        "Total count of ops by type of operation and the error if there was.",+        labelnames=["type", "error"],+    )+    MEMCACHED_OPS_PROCESSING_TIME = prometheus_client.Histogram(+        "guillotina_cache_memcached_ops_processing_time_seconds",+        "Histogram of operations processing time by type (in seconds)",+        labelnames=["type"],+    )++    class watch(metrics.watch):+        def __init__(self, operation: str):+            super().__init__(+                counter=MEMCACHED_OPS,+                histogram=MEMCACHED_OPS_PROCESSING_TIME,+                labels={"type": operation},+                error_mappings={"timeout": asyncio.TimeoutError},+            )+++except ImportError:+    watch = metrics.watch  # type: ignore+++logger = logging.getLogger("guillotina.contrib.memcached")+++class MemcachedDriver:+    """+    Implements a cache driver using Memcached+    """++    def __init__(self):+        self._client: Optional[emcache.Client] = None+        self.initialized: bool = False+        self.init_lock = asyncio.Lock()++    @property+    def client(self) -> Optional[emcache.Client]:+        return self._client++    def _get_client(self) -> emcache.Client:+        if self._client is None:+            raise NoMemcachedConfigured("Memcached client not initialized")+        return self._client++    async def initialize(self, loop):+        async with self.init_lock:+            if self.initialized is False:+                try:+                    await self._connect()+                    self.initialized = True+                except Exception:  # pragma: no cover+                    logger.error("Error initializing memcached driver", exc_info=True)++    async def _create_client(self, settings: Dict[str, Any]) -> emcache.Client:+        hosts = settings.get("hosts")+        if hosts is None or len(hosts) == 0:+            raise NoMemcachedConfigured("No hosts configured")++        # expected hosts format: ["server1:11211", "server2:11211", ...]+        servers = [+            emcache.MemcachedHostAddress(host, int(port)) for host, port in map(lambda x: x.split(":"), hosts)+        ]+        # Configure client constructor from settings+        client_params = {}+        for param in [+            "timeout",+            "max_connections",+            "purge_unused_connections_after",+            "connection_timeout",+            "purge_unhealthy_nodes",+        ]:+            if param in settings and settings[param] is not None:+                client_params[param] = settings[param]+        with watch("connect"):+            return await emcache.create_client(servers, **client_params)++    @backoff.on_exception(backoff.expo, (OSError,), max_time=30, max_tries=4)+    async def _connect(self):+        try:+            settings = app_settings["memcached"]+        except KeyError:+            raise NoMemcachedConfigured("Memcached settings not found")+        self._client = await self._create_client(settings)++    async def finalize(self):+        if self._client is not None:+            await self._client.close()+        self.initialized = False++    async def info(self):+        # emcache client does not support getting stats yet+        return None++    # VALUE API++    async def set(self, key: str, data: bytes, *, expire: Optional[int] = None) -> None:+        client = self._get_client()+        kwargs: Dict[str, int] = {}+        if expire is not None:+            kwargs["exptime"] = expire+        with watch("set"):+            await client.set(key.encode(), data, **kwargs)++    async def get(self, key: str) -> Optional[bytes]:+        client = self._get_client()+        with watch("get") as w:+            item: Optional[emcache.Item] = await client.get(key.encode())+            if item is None:+                # cache miss+                w.labels["type"] = "get_miss"+                return None+            else:+                # cache hit+                return item.value++    async def delete(self, key: str) -> None:+        client = self._get_client()+        with watch("delete"):+            await client.delete(key.encode(), noreply=True)++    async def delete_all(self, keys: List[str]) -> None:+        client = self._get_client()+        with watch("delete_many"):+            for key in keys:+                try:+                    await client.delete(key.encode(), noreply=True)

let's add specific metric here then for delete

lferran

comment created time in 3 hours

PullRequestReviewEvent
PullRequestReviewEvent

push eventplone/guillotina

vangheem

commit sha 76fe4e2359733e823a81c3c691dc53dbb92c1cbb

fix

view details

push time in 3 hours

pull request commentplone/guillotina

Add metrics for in-memory cache

coverage reporting isn't making any sense right here...

vangheem

comment created time in 3 hours

PR opened plone/guillotina

Reviewers
Add metrics for in-memory cache
+121 -11

0 comment

5 changed files

pr created time in 3 hours

create barnchplone/guillotina

branch : in-memory-metrics

created branch time in 3 hours

created tagplone/guillotina

tag5.3.52

Python AsyncIO data API to manage billions of resources

created time in 5 hours

push eventplone/guillotina

vangheem

commit sha 19249ecc8dc5da46a61719c2c7b0d8ad65ed0d3a

Preparing release 5.3.52

view details

vangheem

commit sha 53e83f956c59d4fc11cd5aa1f8acaae394ebb005

Back to development: 5.3.53

view details

push time in 5 hours

pull request commentplone/guillotina

Add id checker for move (#1012)

5.3.52 released

Qiwn

comment created time in 5 hours

push eventplone/guillotina

Qiwn

commit sha 5683fe47fabe5a88a121c390e9c0462ec7cb60a4

Add id checker for move (#1012) (#1013)

view details

push time in 5 hours

PR merged plone/guillotina

Reviewers
Add id checker for move (#1012)
+24 -2

1 comment

4 changed files

Qiwn

pr closed time in 5 hours

delete branch plone/guillotina

delete branch : 5.x-add-id-checker-for-move

delete time in 5 hours

PullRequestReviewEvent

delete branch plone/guillotina

delete branch : add-id-checker-for-move

delete time in 6 hours

push eventplone/guillotina

Qiwn

commit sha 7c0efed8435f1efe287756e045ff58bce9539424

Add id checker for move (#1012)

view details

push time in 6 hours

PR merged plone/guillotina

Reviewers
Add id checker for move
+22 -2

1 comment

4 changed files

Qiwn

pr closed time in 6 hours

delete branch plone/guillotina

delete branch : backport-github-actions

delete time in 6 hours

push eventplone/guillotina

Ferran Llamas

commit sha d3cae43a44fcea4b07da88769fe493688b17fa81

[5.x] github actions (#1011)

view details

push time in 6 hours

PR merged plone/guillotina

Reviewers
[5.x] github actions

instead of slow travis

+81 -79

0 comment

3 changed files

lferran

pr closed time in 6 hours

PullRequestReviewEvent

pull request commentguillotinaweb/pytest-docker-fixtures

add memcached

1.3.11 released. Thanks!

lferran

comment created time in 7 hours

created tagguillotinaweb/pytest-docker-fixtures

tag1.3.11

created time in 7 hours

created tagguillotinaweb/pytest-docker-fixtures

tag1.3.10

created time in 7 hours

push eventguillotinaweb/pytest-docker-fixtures

vangheem

commit sha 6acb365644b2949f9ac96e1b5aa445747743bdb1

Preparing release 1.3.10

view details

vangheem

commit sha 80065420d6bae3129f273c1b327cc446d999fa3b

bump

view details

vangheem

commit sha 8fc15f7a1b78d0f38bb1b05f14690412388ad8a2

Preparing release 1.3.11

view details

vangheem

commit sha c3a8b39c4c7537b415a77b23d021f442eb7fe621

Back to development: 1.3.12

view details

push time in 7 hours

delete branch guillotinaweb/pytest-docker-fixtures

delete branch : memcached

delete time in 7 hours

push eventguillotinaweb/pytest-docker-fixtures

Ferran Llamas

commit sha 209e1311ae7d1f6d3d60ad7cf6be96065df8651b

add memcached (#21)

view details

push time in 7 hours

PullRequestReviewEvent

PR opened onna/kafkaesk

Reviewers
Add rebalance metric
+71 -5

0 comment

6 changed files

pr created time in 5 days

push eventonna/kafkaesk

vangheem

commit sha 2785836d6fdf67ebc7847e6a5ec30c1302e0c26f

bump

view details

push time in 5 days

create barnchonna/kafkaesk

branch : add-rebalanc-metric

created branch time in 5 days

Pull request review commentguillotinaweb/pytest-docker-fixtures

add memcached

+from ._base import BaseImage+from pymemcache.client.base import Client

can lazy import inside check function?

lferran

comment created time in 5 days

PullRequestReviewEvent
PullRequestReviewEvent

created tagplone/guillotina

tag5.3.51

Python AsyncIO data API to manage billions of resources

created time in 6 days

push eventplone/guillotina

vangheem

commit sha 044f1027eb935d052e235b3dc1c126d6e1d56ea0

Preparing release 5.3.51

view details

vangheem

commit sha 0553f6a75304f69d8a3220ec5f2d32e392070587

Back to development: 5.3.52

view details

push time in 6 days

delete branch plone/guillotina

delete branch : 5-x-metrics-on-locks

delete time in 6 days

push eventplone/guillotina

Nathan Van Gheem

commit sha 583488053085c5c255db116c906a7183a0b1d160

More metrics (#1009)

view details

push time in 6 days

PR merged plone/guillotina

More metrics
  • Record metrics on time waiting for pg locks: will help us understand how much shared connection is affecting us.
  • Record hit/miss metrics on cache implementation: help us measure in-memory cache performance of root/container vs non-root objects
+326 -37

3 comments

5 changed files

vangheem

pr closed time in 6 days

push eventplone/guillotina

vangheem

commit sha bf84b3671465e56778d3d43e0857f06603fcd4f0

tweak

view details

push time in 6 days

push eventplone/guillotina

vangheem

commit sha 19c9b76db1fcc51f740b5dd9b1af4babd417e2cd

cl

view details

push time in 6 days

pull request commentplone/guillotina

More metrics

@masipcat @bloodbare ready for another look.

Once we know we're done with adding metrics, I'll forward port these to master.

vangheem

comment created time in 6 days

push eventplone/guillotina

vangheem

commit sha defbd6d40c011aacd053f8940eabe4156dba1358

handle empty

view details

push time in 6 days

push eventplone/guillotina

vangheem

commit sha 7f9fcde0773820e14c852fd48cbb6a675c26ee2d

add metrics on cache hits/misses in cache implementation

view details

push time in 6 days

pull request commentplone/guillotina

Record metrics on time waiting for pg locks

I'm actually going to add some more metrics yet...

I'm trying to see if there is a way to isolate some reporting so we have a way of not reporting cache hit/misses on root type objects... they are screwing up the metrics since they will almost always be in cache.

vangheem

comment created time in 6 days

pull request commentplone/guillotina

Record metrics on time waiting for pg locks

@masipcat I know, he messaged me haha :)

vangheem

comment created time in 6 days

PR opened plone/guillotina

Reviewers
Record metrics on time waiting for pg locks

Will help us understand how much shared connection is affecting us.

+113 -31

0 comment

4 changed files

pr created time in 6 days

create barnchplone/guillotina

branch : 5-x-metrics-on-locks

created branch time in 6 days

created tagplone/guillotina

tag5.3.50

Python AsyncIO data API to manage billions of resources

created time in 7 days

push eventplone/guillotina

vangheem

commit sha 6bbc13b8a79fd12b69f3304726bed1e756e35f44

Preparing release 5.3.50

view details

vangheem

commit sha d45f9f66f1321704b6a4a74a4ee41a254040de5d

Back to development: 5.3.51

view details

push time in 7 days

delete branch plone/guillotina

delete branch : 5-x-record-cache-misses

delete time in 7 days

push eventplone/guillotina

Nathan Van Gheem

commit sha 541a059e2ed81c0548125cce3cba54dbf2260ebd

[5.x] record redis cache misses (#1008)

view details

push time in 7 days

PR merged plone/guillotina

Reviewers
[5.x] record redis cache misses
+26 -3

0 comment

4 changed files

vangheem

pr closed time in 7 days

pull request commentplone/guillotina

memcached objects cache driver

@lferran @pfreixes had pointed out that we need to record cache misses separately. See https://github.com/plone/guillotina/pull/1008 for reference.

lferran

comment created time in 7 days

PR opened plone/guillotina

Reviewers
[5.x] record redis cache misses
+26 -3

0 comment

4 changed files

pr created time in 7 days

create barnchplone/guillotina

branch : 5-x-record-cache-misses

created branch time in 7 days

PullRequestReviewEvent

Pull request review commentplone/guillotina

memcached objects cache driver

 async def set(self, key: str, data: str, *, expire: Optional[int] = None) -> Non         kwargs: Dict[Any] = {}         if expire is not None:             kwargs["exptime"] = expire-        await client.set(key.encode(), data.encode(), **kwargs)+        with watch("set"):+            await client.set(key.encode(), data.encode(), **kwargs)      async def get(self, key: str) -> Optional[bytes]:         client = self._get_client()-        item: Optional[emcache.Item] = await client.get(key.encode())+        with watch("get"):+            item: Optional[emcache.Item] = await client.get(key.encode())         if item is not None:             return item.value         else:             return None      async def delete(self, key: str) -> None:         client = self._get_client()-        await client.delete(key.encode())+        with watch("delete"):+            await client.delete(key.encode())      async def delete_all(self, keys: List[str]) -> None:         client = self._get_client()         for key in keys:             try:-                await client.delete(key.encode())+                with watch("delete_many"):

Maybe you could has a watch outside the for loop to measure how long deleting all the keys inside a request take?

lferran

comment created time in 7 days

Pull request review commentplone/guillotina

memcached objects cache driver

 async def set(self, key: str, data: str, *, expire: Optional[int] = None) -> Non         kwargs: Dict[Any] = {}         if expire is not None:             kwargs["exptime"] = expire-        await client.set(key.encode(), data.encode(), **kwargs)+        with watch("set"):+            await client.set(key.encode(), data.encode(), **kwargs)      async def get(self, key: str) -> Optional[bytes]:         client = self._get_client()-        item: Optional[emcache.Item] = await client.get(key.encode())+        with watch("get"):+            item: Optional[emcache.Item] = await client.get(key.encode())         if item is not None:             return item.value         else:             return None      async def delete(self, key: str) -> None:         client = self._get_client()-        await client.delete(key.encode())+        with watch("delete"):+            await client.delete(key.encode())      async def delete_all(self, keys: List[str]) -> None:         client = self._get_client()         for key in keys:             try:-                await client.delete(key.encode())+                with watch("delete_many"):

These are all single deletes!

                with watch("delete"):
lferran

comment created time in 7 days

PullRequestReviewEvent
PullRequestReviewEvent

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha d754f63592cd2727a3dc312ad39e0f678ce48817

add prometheus to tests

view details

push time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha 3bf2f9517a80df52658239d61b4ef4419e5af9c0

agin

view details

push time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha 1bb8fe555fd591da275668fae1012ce58deac1bf

flake

view details

push time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha f5b67a5368a0a18b72ca2d29cd357deccb651c96

pin black version

view details

push time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha 6262290fd8e6e4811e4151f7ffbcb2b23fc11135

pin black version

view details

push time in 8 days

created tagguillotinaweb/guillotina_amqp

tag5.0.21

created time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha a8b1c46095b80bcdc2c9547845c4030120eed3c1

Preparing release 5.0.21

view details

vangheem

commit sha 148e0f50106c82e7cebe123daa0dd0074870a5d4

Back to development: 5.0.22

view details

push time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha baf6b7c7ebdebd6d9102d7ddbeb406d67a62e699

fix getting metric

view details

push time in 8 days

push eventguillotinaweb/guillotina_amqp

vangheem

commit sha 3dc9f2f8a61cc7833f3acec46332a25605d3e379

only conditionally label

view details

push time in 8 days

Pull request review commentguillotinaweb/pytest-docker-fixtures

add memcached

+from ._base import BaseImage+from time import sleep+++class Memcached(BaseImage):+    label = 'memcached'+    name = 'memcached'+    port = 11211++    def check(self):+        sleep(1)

Could we check tcp port or somethign here?

lferran

comment created time in 8 days

PullRequestReviewEvent
PullRequestReviewEvent

created tagplone/guillotina

tag5.3.49

Python AsyncIO data API to manage billions of resources

created time in 8 days

push eventplone/guillotina

vangheem

commit sha 07856fe7dbe2fa9a42e05e67902874ded9102727

Preparing release 5.3.49

view details

vangheem

commit sha b57a9be8f32061fd755f83a99295e73f63eb3693

Back to development: 5.3.50

view details

push time in 8 days

delete branch plone/guillotina

delete branch : 5-x-metrics

delete time in 8 days

push eventplone/guillotina

Nathan Van Gheem

commit sha 3ebe744b2024ddee4b36415284c578e3e17836b3

[5.x] Add prometheus metrics to pg and redis operations (#1005)

view details

push time in 8 days

push eventplone/guillotina

vangheem

commit sha c991eb9ef2116513c390ad83907b64e7e94990ba

mypy!

view details

push time in 8 days

push eventplone/guillotina

vangheem

commit sha 183bc397c8782810d5f75b81ec4f1eada8c72102

mypy

view details

push time in 8 days

push eventplone/guillotina

vangheem

commit sha fea188e4ac99aa6053245836c7438c415e692e69

more json

view details

push time in 8 days

PullRequestReviewEvent

Pull request review commentplone/guillotina

[5.x] Add prometheus metrics to pg and redis operations

 async def _save(self):         redis = await self.get_redis()         key = self.get_key()         self._data["last_activity"] = time.time()-        await redis.set(key, json.dumps(self._data, cls=GuillotinaJSONEncoder), expire=self._ttl)+        with watch("set"):+            await redis.set(key, json.dumps(self._data, cls=GuillotinaJSONEncoder), expire=self._ttl)

good idea. I will move it

vangheem

comment created time in 8 days

pull request commentplone/guillotina

[5.x] Add prometheus metrics to pg and redis operations

The idea is to keep guillotina_prometheus to expose these metrics?

Yes, or you can expose them yourself by implementing your own metrics endpoint.

vangheem

comment created time in 8 days

push eventplone/guillotina

vangheem

commit sha 97e13e1b5aeee7af48145f623712a7e8fd672a3e

prometheus only a test dep

view details

push time in 8 days

push eventplone/guillotina

vangheem

commit sha d217738dfc176db052ccb66ca37bf70f334405e5

conditional

view details

push time in 8 days

startedulid/spec

started time in 8 days

push eventplone/guillotina

vangheem

commit sha 247e7be3be8aa4885da41bbf4410528766d910f7

cl

view details

push time in 8 days

PR opened plone/guillotina

Reviewers
[5.x] Add prometheus metrics to pg and redis operations
+422 -120

0 comment

8 changed files

pr created time in 8 days

push eventplone/guillotina

vangheem

commit sha 9ac876b9614a7182506c77f3bee57464b1e6bd69

add tests

view details

push time in 8 days

more