Thanks to visit codestin.com
Credit goes to github.com

Skip to content

NDB: Sketch high level strategy #6908

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

Closed
wants to merge 14 commits into from
Closed

Conversation

chrisrossi
Copy link

Diff base is #6888

This code is intentionally sketchy. It contains very partial implementations, non-conformant docstrings, and less than 100% test coverage. This code is not being proposed for merge but is offered as a sketch for discussion of general strategy and/or a guide for me to follow to produce a more complete, real implementation.

The main point of this was to provide the bare minimum to make the single system test pass. This test uses google.cloud.datastore to write an entity to Datastore and uses google.cloud.ndb to read it back out of Datastore as an instance of an NDB model class. I suggest looking at the test and thinking about if that is the correct user experience.

The salient points are:

  • google.cloud.ndb.Client as a parallel to google.cloud.datastore.Client, as a means of bootstrapping NDB and its connection to Datastore in a way familiar to GCP users. This is the entry point for establishing credentials, the working project/app, and the namespace, exactly like google.cloud.datastore.

  • Client.context() as a context manager for encapsulating code that uses NDB. Under the hood there is a thread local state which legacy NDB previously managed in GAE by attaching it to the running HTTP request, an fixture which is no longer available in GCP. Use of the context manager means most existing projects which use NDB can simply wrap their code in a context and their existing business code continues to work, as it can access any needed state from the running context.

  • _future.Future as a thin wrapper around Futures returned by gRPC. This class is meant to be subclassed and can wrap any number of gRPC Futures and compute an arbitrary result based on the results of those wrapped futures. As an example, there is key.GetByKeyFuture which wraps the return value of a call to Lookup.future() in Datastore's gRPC API and marsahall's an NDB entity from the returned Datastore protocol buffer. It's not doing any async on its own, here, just wrapping the raw gRPC async calls to provide Futures that yield arbitrarily computed results.

I think pretty much everything except the tasklets surface can be implemented in this way. I haven't fully worked out, yet, how this will integrate with the tasklets mini-framework but I think having a lot of the rest fleshed out will give us a good starting point.

@chrisrossi chrisrossi added do not merge Indicates a pull request not ready for merge, due to either quality or timing. api: ndb labels Dec 12, 2018
@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Dec 12, 2018
@chrisrossi chrisrossi requested a review from tseaver December 12, 2018 16:22
state = _runstate.current()
request = datastore_pb2.LookupRequest(project_id=state.project)
key_pb = request.keys.add()
key_pb.CopyFrom(key._key.to_protobuf())

This comment was marked as spam.

This comment was marked as spam.


"""A Future class."""

_NOT_COMPUTED = object()

This comment was marked as spam.

This comment was marked as spam.

# See the License for the specific language governing permissions and
# limitations under the License.

"""A Future class."""

This comment was marked as spam.

This comment was marked as spam.


def get_result(self):
"""Get the computed result for this future."""
if self._result is _NOT_COMPUTED:

This comment was marked as spam.

This comment was marked as spam.

This class is meant to be subclassed with code to compute a result from the
results of the wrapped gRPC futures. :method:`_compute_result` should be
overriden to compute a result from the completed gRPC calls.
"""

This comment was marked as spam.

This comment was marked as spam.


def _compute_result(self, result):
from google.cloud.ndb import model # avoid circular import
return model._entity_from_protobuf(result.found[0].entity)

This comment was marked as spam.

This comment was marked as spam.

class GetByKeyFuture(_future.Future):
"""Future for looking up entities by Key."""

def _compute_result(self, result):

This comment was marked as spam.

This comment was marked as spam.

ds_key = ds_client.key("SomeKind", 1234)
ds_entity = datastore.Entity(key=ds_key)
ds_entity.update({"foo": 42, "bar": "none"})
ds_client.put(ds_entity)

This comment was marked as spam.

This comment was marked as spam.

ds_client = datastore.Client()
ds_key = ds_client.key("SomeKind", 1234)
ds_entity = datastore.Entity(key=ds_key)
ds_entity.update({"foo": 42, "bar": "none"})

This comment was marked as spam.

This comment was marked as spam.

"""
_NOT_COMPUTED = object()
_result = _NOT_COMPUTED
_complete = False

This comment was marked as spam.



def test_retrieve_entity(ds_entity):
ds_entity("SomeKind", 1234, foo=42, bar="none")

This comment was marked as spam.

bar = ndb.StringProperty()

client = ndb.Client()
with client.context():

This comment was marked as spam.

@chrisrossi
Copy link
Author

@dhermes This is good feedback, thanks! This code was meant to be "sketchy", so I could hammer out a basic idea without getting bogged down too far in details. In general, though, I'm just looking to use this to talk about high level approach. If that looks good, I'll start fleshing out the individual components of this "for real", with all relevant coding standards, etc...

@chrisrossi
Copy link
Author

I think I've had a brainstorm for how I can do this in a way that integrates with the tasklet eventloop. This means, basically, starting over on this sketch, so I'm going to close this one and start up a new branch with the new idea.

As difficult as it is to try and see all the moving parts at the same time, simply forging ahead without really taking tasklets into account is likely to paint us into a corner where implementing tasklets isn't really possible without another big rewrite. I think I can do better than that.

@chrisrossi chrisrossi closed this Dec 18, 2018
@dhermes
Copy link
Contributor

dhermes commented Dec 19, 2018

👍

@chrisrossi chrisrossi deleted the sketch branch January 13, 2019 18:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: ndb cla: yes This human has signed the Contributor License Agreement. do not merge Indicates a pull request not ready for merge, due to either quality or timing.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants