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

Using Bluesky tiled_writer callback results in 405 error codes on some endpoints in single-user mode #847

Closed
cjboyle opened this issue Jan 15, 2025 · 2 comments

Comments

@cjboyle
Copy link

cjboyle commented Jan 15, 2025

Hello, I'm currently testing out the tiled_writer via the proposed tutorial (bluesky/bluesky-cookbook#24), though instead of the TempTiledServer I've connected to a dockerized Tiled instance in front of a Postgres database.

Everything seems to be connected properly, in that Bluesky does write the "start" and "stop" documents through Tiled and into the database, but on an intermediate POST request Tiled returns error 405.

To me it seems like the single-user mode user may be missing an authentication scope?

Tiled config:

authentication:
  single_user_api_key: S3CR3T
  # allow_anonymous_access: true

trees:
  - tree: catalog
    path: /
    args:
      uri: postgresql://app:${TILED_DATABASE_PASSWORD}@cnpg-cluster-test-proxy:5432/app
      init_if_not_exists: true
Full stack trace
Run aborted
Traceback (most recent call last):
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/utils.py", line 69, in handle_error
    raise_for_status(response)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/utils.py", line 62, in raise_for_status
    raise httpx.HTTPStatusError(message, request=request, response=response)
httpx.HTTPStatusError: Client error '405 Method Not Allowed' for url 'http://localhost:8000/api/v1/metadata/6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config'
For more information, server admin can search server logs for correlation ID 35077f56481962e3.

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py", line 1605, in _run
    msg = self._plan_stack[-1].send(resp)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plans.py", line 1292, in scan
    return (yield from scan_nd(detectors, full_cycler, per_step=per_step, md=_md))
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plans.py", line 1169, in scan_nd
    return (yield from inner_scan_nd())
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 1260, in dec_inner
    return (yield from plan)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 995, in stage_wrapper
    return (yield from finalize_wrapper(inner(), unstage_devices()))
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 536, in finalize_wrapper
    ret = yield from plan
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 993, in inner
    return (yield from plan)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 1260, in dec_inner
    return (yield from plan)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 358, in run_wrapper
    yield from contingency_wrapper(plan, except_plan=except_plan, else_plan=close_run)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 604, in contingency_wrapper
    ret = yield from plan
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plans.py", line 1167, in inner_scan_nd
    yield from per_step(detectors, step, pos_cache)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 1954, in __iter__
    return (yield from self._iter)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py", line 1734, in one_nd_step
    yield from take_reading(list(detectors) + list(motors))  # type: ignore  # Movable issue
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 1954, in __iter__
    return (yield from self._iter)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py", line 1476, in trigger_and_read
    return (yield from rewindable_wrapper(inner_trigger_and_read(), rewindable))
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 731, in rewindable_wrapper
    return (yield from plan)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py", line 1471, in inner_trigger_and_read
    ret = yield from contingency_wrapper(read_plan(), except_plan=exception_path, else_plan=standard_path)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py", line 623, in contingency_wrapper
    yield from else_plan()
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py", line 1465, in standard_path
    yield from save()
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 1954, in __iter__
    return (yield from self._iter)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py", line 142, in save
    return (yield Msg("save"))
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py", line 1672, in _run
    new_response = await coro(msg)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py", line 2076, in _save
    await current_run.save(msg)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/bundlers.py", line 538, in save
    descriptor_doc, compose_event, d_objs = await self._prepare_stream(desc_key, objs_dks)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/bundlers.py", line 206, in _prepare_stream
    await self.emit(DocumentNames.descriptor, self._descriptors[desc_key].descriptor_doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py", line 2679, in emit
    self.emit_sync(name, doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py", line 2676, in emit_sync
    self.dispatcher.process(name, doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py", line 2699, in process
    exceptions = self.cb_registry.process(name, name.name, doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 433, in process
    func(*args, **kwargs)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py", line 523, in __call__
    return mtd(*args, **kwargs)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/callbacks/tiled_writer.py", line 50, in __call__
    self._run_router(name, doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py", line 191, in __call__
    return self._dispatch(name, doc, validate)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py", line 199, in _dispatch
    output_doc = getattr(self, name)(doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py", line 1606, in descriptor
    callback("descriptor", descriptor_doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py", line 191, in __call__
    return self._dispatch(name, doc, validate)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py", line 199, in _dispatch
    output_doc = getattr(self, name)(doc)
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/callbacks/tiled_writer.py", line 145, in descriptor
    conf_node.new(
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/container.py", line 635, in new
    document = handle_error(
  File "/home/boylec0/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/utils.py", line 84, in handle_error
    raise ClientError(message, exc.request, exc.response) from exc
tiled.client.utils.ClientError: 405: Data cannot be written at the path 6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config http://localhost:8000/api/v1/metadata/6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config
---------------------------------------------------------------------------
HTTPStatusError                           Traceback (most recent call last)
File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/utils.py:69, in handle_error(response)
     68 try:
---> 69     raise_for_status(response)
     70 except httpx.RequestError:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/utils.py:62, in raise_for_status(response)
     59 message = message.format(
     60     response, error_type=error_type, correlation_id=correlation_id
     61 )
---> 62 raise httpx.HTTPStatusError(message, request=request, response=response)

HTTPStatusError: Client error '405 Method Not Allowed' for url 'http://localhost:8000/api/v1/metadata/6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config'
For more information, server admin can search server logs for correlation ID 35077f56481962e3.

The above exception was the direct cause of the following exception:

ClientError                               Traceback (most recent call last)
Cell In[5], line 3
      1 # Run the acquisition
      2 docs.clear()
----> 3 scan_id, = RE(bp.scan([det], motor, -5, 5, 10))
      4 print(f"Finished aquisition: {scan_id=}")

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:973, in RunEngine.__call__(self, *args, **metadata_kw)
    969         self._blocking_event.set()
    971     self._task_fut.add_done_callback(set_blocking_event)
--> 973 plan_return = self._resume_task(init_func=_build_task)
    975 if self._interrupted:
    976     raise RunEngineInterrupted(self.pause_msg) from None

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:1109, in RunEngine._resume_task(self, init_func)
   1106 # if the main task exception is not None, re-raise
   1107 # it (unless it is a canceled error)
   1108 if exc is not None and not isinstance(exc, _RunEnginePanic):
-> 1109     raise exc
   1110 # Only try to get a result if there wasn't an error,
   1111 # (other than a cancelled error)
   1112 if exc is None:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:1751, in RunEngine._run(self)
   1749     exit_reason = str(err)
   1750     self.log.exception("Run aborted")
-> 1751     raise err
   1752 finally:
   1753     if not exit_reason:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:1605, in RunEngine._run(self)
   1602 # The normal case of clean operation
   1603 else:
   1604     try:
-> 1605         msg = self._plan_stack[-1].send(resp)
   1606     # We have exhausted the top generator
   1607     except StopIteration:
   1608         # pop the dead generator go back to the top

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plans.py:1292, in scan(detectors, num, per_step, md, *args)
   1288 _md["hints"].update(md.get("hints", {}) or {})  # type: ignore
   1290 full_cycler = plan_patterns.inner_product(num=num, args=args)
-> 1292 return (yield from scan_nd(detectors, full_cycler, per_step=per_step, md=_md))

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plans.py:1169, in scan_nd(detectors, cycler, per_step, md)
   1166     for step in list(cycler):
   1167         yield from per_step(detectors, step, pos_cache)
-> 1169 return (yield from inner_scan_nd())

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:1260, in make_decorator.<locals>.dec_outer.<locals>.dec.<locals>.dec_inner(*inner_args, **inner_kwargs)
   1258 plan = gen_func(*inner_args, **inner_kwargs)
   1259 plan = wrapper(plan, *args, **kwargs)
-> 1260 return (yield from plan)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:995, in stage_wrapper(plan, devices)
    992     yield from stage_devices()
    993     return (yield from plan)
--> 995 return (yield from finalize_wrapper(inner(), unstage_devices()))

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:536, in finalize_wrapper(plan, final_plan, pause_for_debug)
    534 cleanup = True
    535 try:
--> 536     ret = yield from plan
    537 except GeneratorExit:
    538     cleanup = False

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:993, in stage_wrapper.<locals>.inner()
    991 def inner():
    992     yield from stage_devices()
--> 993     return (yield from plan)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:1260, in make_decorator.<locals>.dec_outer.<locals>.dec.<locals>.dec_inner(*inner_args, **inner_kwargs)
   1258 plan = gen_func(*inner_args, **inner_kwargs)
   1259 plan = wrapper(plan, *args, **kwargs)
-> 1260 return (yield from plan)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:358, in run_wrapper(plan, md)
    355     else:
    356         yield from close_run(exit_status="fail", reason=str(e))
--> 358 yield from contingency_wrapper(plan, except_plan=except_plan, else_plan=close_run)
    359 return rs_uid

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:604, in contingency_wrapper(plan, except_plan, else_plan, final_plan, pause_for_debug, auto_raise)
    602 cleanup = True
    603 try:
--> 604     ret = yield from plan
    605 except GeneratorExit:
    606     cleanup = False

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plans.py:1167, in scan_nd.<locals>.inner_scan_nd()
   1165     yield from bps.declare_stream(*motors, *detectors, name="primary")
   1166 for step in list(cycler):
-> 1167     yield from per_step(detectors, step, pos_cache)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:1954, in Plan.__iter__(self)
   1952 def __iter__(self):
   1953     self._stack = None
-> 1954     return (yield from self._iter)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py:1734, in one_nd_step(detectors, step, pos_cache, take_reading)
   1732 motors = step.keys()
   1733 yield from move_per_step(step, pos_cache)
-> 1734 yield from take_reading(list(detectors) + list(motors))

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:1954, in Plan.__iter__(self)
   1952 def __iter__(self):
   1953     self._stack = None
-> 1954     return (yield from self._iter)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py:1476, in trigger_and_read(devices, name)
   1472     return ret
   1474 from .preprocessors import rewindable_wrapper
-> 1476 return (yield from rewindable_wrapper(inner_trigger_and_read(), rewindable))

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:731, in rewindable_wrapper(plan, rewindable)
    729     return (yield from finalize_wrapper(plan, restore_rewindable()))
    730 else:
--> 731     return (yield from plan)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py:1471, in trigger_and_read.<locals>.inner_trigger_and_read()
   1468     yield from drop()
   1469     raise exp
-> 1471 ret = yield from contingency_wrapper(read_plan(), except_plan=exception_path, else_plan=standard_path)
   1472 return ret

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/preprocessors.py:623, in contingency_wrapper(plan, except_plan, else_plan, final_plan, pause_for_debug, auto_raise)
    621 else:
    622     if else_plan:
--> 623         yield from else_plan()
    624 finally:
    625     # if the exception raised in `GeneratorExit` that means
    626     # someone called `gen.close()` on this generator.  In those
   (...)
    632 
    633     # https://docs.python.org/3/reference/expressions.html?#generator.close
    634     if cleanup and final_plan:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py:1465, in trigger_and_read.<locals>.inner_trigger_and_read.<locals>.standard_path()
   1464 def standard_path():
-> 1465     yield from save()

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:1954, in Plan.__iter__(self)
   1952 def __iter__(self):
   1953     self._stack = None
-> 1954     return (yield from self._iter)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/plan_stubs.py:142, in save()
    128 @plan
    129 def save() -> MsgGenerator:
    130     """
    131     Close a bundle of readings and emit a completed Event document.
    132 
   (...)
    140     :func:`bluesky.plan_stubs.create`
    141     """
--> 142     return (yield Msg("save"))

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:1672, in RunEngine._run(self)
   1667 # try to finally run the command the user asked for
   1668 try:
   1669     # this is one of two places that 'async'
   1670     # exceptions (coming in via throw) can be
   1671     # raised
-> 1672     new_response = await coro(msg)
   1674 # special case `CancelledError` and let the outer
   1675 # exception block deal with it.
   1676 except asyncio.CancelledError:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:2076, in RunEngine._save(self, msg)
   2074     raise IllegalMessageSequence(ims_msg)
   2075 else:
-> 2076     await current_run.save(msg)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/bundlers.py:538, in RunBundler.save(self, msg)
    535         await self._ensure_cached(obj, collect=isinstance(obj, Collectable))
    536         objs_dks[obj] = self._describe_cache[obj]
--> 538     descriptor_doc, compose_event, d_objs = await self._prepare_stream(desc_key, objs_dks)
    540 # do have the descriptor cached
    541 elif frozenset(d_objs) != objs_read:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/bundlers.py:206, in RunBundler._prepare_stream(self, desc_key, objs_dks)
    193     config[obj.name] = {
    194         "data": self._config_values_cache[obj],
    195         "timestamps": self._config_ts_cache[obj],
    196         "data_keys": self._config_desc_cache[obj],
    197     }
    199 self._descriptors[desc_key] = self._compose_descriptor(
    200     desc_key,
    201     data_keys,
   (...)
    204     object_keys=object_keys,
    205 )
--> 206 await self.emit(DocumentNames.descriptor, self._descriptors[desc_key].descriptor_doc)
    207 doc_logger.debug(
    208     "[descriptor] document emitted with name %r containing data keys %r (run_uid=%r)",
    209     desc_key,
   (...)
    212     extra={"doc_name": "descriptor", "run_uid": self._run_start_uid, "data_keys": data_keys.keys()},
    213 )
    214 self._descriptor_objs[desc_key] = objs_dks

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:2679, in RunEngine.emit(self, name, doc)
   2678 async def emit(self, name, doc):
-> 2679     self.emit_sync(name, doc)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:2676, in RunEngine.emit_sync(self, name, doc)
   2673 "Process blocking callbacks and schedule non-blocking callbacks."
   2675 # Process the doc, already validated against the schema in event-model
-> 2676 self.dispatcher.process(name, doc)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/run_engine.py:2699, in Dispatcher.process(self, name, doc)
   2690 def process(self, name, doc):
   2691     """
   2692     Dispatch document ``doc`` of type ``name`` to the callback registry.
   2693 
   (...)
   2697     doc : dict
   2698     """
-> 2699     exceptions = self.cb_registry.process(name, name.name, doc)
   2700     for exc, traceback in exceptions:  # noqa: B007
   2701         warn(  # noqa: B028
   2702             "A %r was raised during the processing of a %s "  # noqa: UP031
   2703             "Document. The error will be ignored to avoid "
   (...)
   2706             "and run again." % (exc, name.name)
   2707         )

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:433, in CallbackRegistry.process(self, sig, *args, **kwargs)
    431 for cid, func in list(self.callbacks[sig].items()):  # noqa: B007
    432     try:
--> 433         func(*args, **kwargs)
    434     except ReferenceError:
    435         self._remove_proxy(func)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/utils/__init__.py:523, in _BoundMethodProxy.__call__(self, *args, **kwargs)
    521     mtd = self.func
    522 # invoke the callable and return the result
--> 523 return mtd(*args, **kwargs)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/callbacks/tiled_writer.py:50, in TiledWriter.__call__(self, name, doc)
     49 def __call__(self, name, doc):
---> 50     self._run_router(name, doc)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py:191, in DocumentRouter.__call__(self, name, doc, validate)
    171 def __call__(
    172     self, name: str, doc: dict, validate: bool = False
    173 ) -> Tuple[str, dict]:
    174     """
    175     Process a document.
    176 
   (...)
    189         instance as doc, a copy of doc, or a different dict altogether.
    190     """
--> 191     return self._dispatch(name, doc, validate)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py:199, in DocumentRouter._dispatch(self, name, doc, validate)
    193 def _dispatch(self, name: str, doc: dict, validate: bool) -> Tuple[str, dict]:
    194     """
    195     Dispatch to the method corresponding to the `name`.
    196 
    197     Optionally validate that the result is still a valid document.
    198     """
--> 199     output_doc = getattr(self, name)(doc)
    201     # If 'event' is not defined by the subclass but 'event_page' is, or
    202     # vice versa, use that. And the same for 'datum_page' / 'datum.
    203     if output_doc is NotImplemented:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py:1606, in RunRouter.descriptor(self, descriptor_doc)
   1604 self._factory_cbs_by_descriptor[descriptor_uid].extend(factory_cbs)
   1605 for callback in factory_cbs:
-> 1606     callback("descriptor", descriptor_doc)
   1607 # Let all the subfactories add any relevant callbacks.
   1608 for subfactory in self._subfactories[start_uid]:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py:191, in DocumentRouter.__call__(self, name, doc, validate)
    171 def __call__(
    172     self, name: str, doc: dict, validate: bool = False
    173 ) -> Tuple[str, dict]:
    174     """
    175     Process a document.
    176 
   (...)
    189         instance as doc, a copy of doc, or a different dict altogether.
    190     """
--> 191     return self._dispatch(name, doc, validate)

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/event_model/__init__.py:199, in DocumentRouter._dispatch(self, name, doc, validate)
    193 def _dispatch(self, name: str, doc: dict, validate: bool) -> Tuple[str, dict]:
    194     """
    195     Dispatch to the method corresponding to the `name`.
    196 
    197     Optionally validate that the result is still a valid document.
    198     """
--> 199     output_doc = getattr(self, name)(doc)
    201     # If 'event' is not defined by the subclass but 'event_page' is, or
    202     # vice versa, use that. And the same for 'datum_page' / 'datum.
    203     if output_doc is NotImplemented:

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/bluesky/callbacks/tiled_writer.py:145, in _RunWriter.descriptor(self, doc)
    143         conf_node[det_name].append_partition(df, 0)
    144     else:
--> 145         conf_node.new(
    146             structure_family=StructureFamily.table,
    147             data_sources=[
    148                 DataSource(
    149                     structure_family=StructureFamily.table,
    150                     structure=TableStructure.from_pandas(df),
    151                     mimetype="text/csv",
    152                 ),
    153             ],
    154             key=det_name,
    155             metadata=det_dict["data_keys"],
    156         )
    157         conf_node[det_name].write_partition(df, 0)
    159 self._desc_nodes[uid] = desc_node

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/container.py:635, in Container.new(self, structure_family, data_sources, key, metadata, specs)
    632 else:
    633     endpoint = self.uri
--> 635 document = handle_error(
    636     self.context.http_client.post(
    637         endpoint,
    638         headers={"Accept": MSGPACK_MIME_TYPE},
    639         content=safe_json_dump(body),
    640     )
    641 ).json()
    643 if structure_family == StructureFamily.container:
    644     structure = {"contents": None, "count": None}

File ~/.pyenv/versions/3.10.14/lib/python3.10/site-packages/tiled/client/utils.py:84, in handle_error(response)
     82         detail = response.reason_phrase
     83     message = f"{exc.response.status_code}: " f"{detail} " f"{exc.request.url}"
---> 84     raise ClientError(message, exc.request, exc.response) from exc
     85 else:
     86     raise

ClientError: 405: Data cannot be written at the path 6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config http://localhost:8000/api/v1/metadata/6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config
Tiled server output
tiled_test  | [88159cdefbfd454f] 127.0.0.1:39592 (public) - "GET /healthz HTTP/1.1" 200 OK
tiled_test  | [dfd1a837f8bbd8b1] 127.0.0.1:35812 (public) - "GET /healthz HTTP/1.1" 200 OK
tiled_test  | [fd058ac008a0f753] 127.0.0.1:48538 (public) - "GET /api/v1/ HTTP/1.1" 200 OK
tiled_test  | [73efba7fee7d5628] 127.0.0.1:48538 (admin) - "GET /api/v1/metadata/?include_data_sources=false HTTP/1.1" 200 OK
tiled_test  | [1146dd63d37dc028] 127.0.0.1:48538 (admin) - "POST /api/v1/metadata/ HTTP/1.1" 200 OK
tiled_test  | [56167a5071415ea4] 127.0.0.1:48538 (admin) - "GET /api/v1/search//6fc4119b-6c77-40a3-a7a4-e33ecffc015e?page%5Boffset%5D=0&fields=&sort= HTTP/1.1" 200 OK
tiled_test  | [63194b424ec43faf] 127.0.0.1:48538 (admin) - "POST /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e HTTP/1.1" 200 OK
tiled_test  | [dc846f24e60c08b2] 127.0.0.1:48538 (admin) - "POST /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary HTTP/1.1" 200 OK
tiled_test  | [350a79e71b9d0adb] 127.0.0.1:48538 (admin) - "POST /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary HTTP/1.1" 200 OK
tiled_test  | [21a712d746ad1633] 127.0.0.1:48538 (admin) - "POST /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary HTTP/1.1" 200 OK
tiled_test  | [f45d2ff9021c98ba] 127.0.0.1:48538 (admin) - "PATCH /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary HTTP/1.1" 200 OK
tiled_test  | [e857850eee048fe3] 127.0.0.1:48538 (admin) - "GET /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config HTTP/1.1" 200 OK
tiled_test  | [74b75cb9795b4d89] 127.0.0.1:48538 (admin) - "GET /api/v1/search/6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config?page%5Boffset%5D=0&fields=&sort= HTTP/1.1" 200 OK
tiled_test  | [35077f56481962e3] 127.0.0.1:48538 (admin) - "POST /api/v1/metadata/6fc4119b-6c77-40a3-a7a4-e33ecffc015e/primary/config HTTP/1.1" 405 Method Not Allowed
tiled_test  | [7b7310ff91ae46f2] 127.0.0.1:48538 (admin) - "PATCH /api/v1/metadata//6fc4119b-6c77-40a3-a7a4-e33ecffc015e HTTP/1.1" 200 OK
tiled_test  | [c19abb7c3d22e536] 127.0.0.1:48544 (public) - "GET /healthz HTTP/1.1" 200 OK
tiled_test  | [2a4bb76f45208e9b] 127.0.0.1:52498 (public) - "GET /healthz HTTP/1.1" 200 OK
tiled_test  | [6e5cb5078588c0ec] 127.0.0.1:53892 (public) - "GET /healthz HTTP/1.1" 200 OK

Database screenshot:
image

@danielballan
Copy link
Member

danielballan commented Jan 16, 2025

As a quick answer, not having thoroughly checked, I think the issue is that the server config must include an area where tiled can write data files.

args:
      uri: postgresql://app:${TILED_DATABASE_PASSWORD}@cnpg-cluster-test-proxy:5432/app
      init_if_not_exists: true
      writable_storage: /tmp/test

Be advised that this is still under active development and not recommended for storing anything important just yet. We use it at one instrument at NSLS-II, under careful management.

@cjboyle
Copy link
Author

cjboyle commented Jan 16, 2025

Adding writable_storage fixed it, thanks!

@cjboyle cjboyle closed this as completed Jan 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants