Skip to content

Commit 4f17856

Browse files
authored
OperationsStub and Operation<ResultT, MetadataT> (googleapis#33)
* Basic tests, intf, and impl for OperationsStub and Operation<ResultT, MetadataT> OperationsStub is a gax-owned abstract class, similar to the GAPIC stub, that defines three rpc wrappers: GetOperation, DeleteOperation, and CancelOperation. GAPIC stubs for clients that define long running operations and include operations.proto will inherit from OperationsStub and provide overrides for the three methods. OperationsClient is a gax-owned concrete class, similar to the GAPIC client, that is responsible for updating, deleting, or canceling an operation. Operation<ResultT, MetadataT> is a user-visible primitive for interacting with long-running operations. It is a type-safe wrapper around google::longrunning::Operation. In the future, an alternative, simpler interface that hides the details of gax::Operation will be exposed that returns a future object. A separate review will add a method to GAPIC clients that returns an OperationsClient sharing the same underlying stub. A separate review will use protobuf annotations to detect client methods that should return gax::Operation and what the types of its template parameters should be.
1 parent b75840c commit 4f17856

13 files changed

+772
-17
lines changed

WORKSPACE

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
workspace(name = "com_google_gapic_generator_cpp")
1616

17+
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
1718
load(
1819
"//gax:repositories.bzl",
1920
"com_google_gapic_generator_cpp_gax_repositories",
@@ -29,3 +30,56 @@ com_google_gapic_generator_cpp_repositories()
2930
load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps")
3031

3132
grpc_deps()
33+
34+
# WARNING: The java and go segments below are a hack to get
35+
# C++ operations proto types to build.
36+
# Tracked by https://github.com/googleapis/gapic-generator-cpp/issues/35
37+
38+
##############################################################################
39+
# Java
40+
##############################################################################
41+
42+
#
43+
# gapic-generator
44+
#
45+
http_archive(
46+
name = "com_google_api_codegen",
47+
urls = ["https://github.com/googleapis/gapic-generator/archive/96c3c5a4c8397d4bd29a6abce861547a271383e1.zip"],
48+
strip_prefix = "gapic-generator-96c3c5a4c8397d4bd29a6abce861547a271383e1",
49+
)
50+
51+
#
52+
# java_gapic artifacts runtime dependencies (gax-java)
53+
#
54+
load("@com_google_api_codegen//rules_gapic/java:java_gapic_repositories.bzl", "java_gapic_repositories")
55+
56+
java_gapic_repositories()
57+
58+
load("@com_google_api_gax_java//:repository_rules.bzl", "com_google_api_gax_java_properties")
59+
60+
com_google_api_gax_java_properties(
61+
name = "com_google_api_gax_java_properties",
62+
file = "@com_google_api_gax_java//:dependencies.properties",
63+
)
64+
65+
load("@com_google_api_gax_java//:repositories.bzl", "com_google_api_gax_java_repositories")
66+
67+
com_google_api_gax_java_repositories()
68+
##############################################################################
69+
# Go
70+
##############################################################################
71+
72+
#
73+
# rules_go (support Golang under bazel)
74+
#
75+
http_archive(
76+
name = "io_bazel_rules_go",
77+
strip_prefix = "rules_go-7d17d496a6b32f6a573c6c22e29c58204eddf3d4",
78+
urls = ["https://github.com/bazelbuild/rules_go/archive/7d17d496a6b32f6a573c6c22e29c58204eddf3d4.zip"],
79+
)
80+
81+
load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies")
82+
83+
go_rules_dependencies()
84+
85+
go_register_toolchains()

gax/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,44 @@ package(default_visibility = ["//visibility:public"])
1616

1717
licenses(["notice"]) # Apache 2.0
1818

19+
# Note: googleapis doesn't define a cc_proto_library for operations_proto,
20+
# so declare one here ourselves.
21+
cc_proto_library(
22+
name = "longrunning_cpp_proto",
23+
deps = ["@com_google_googleapis//google/longrunning:operations_proto"],
24+
)
25+
1926
cc_library(
2027
name = "gax",
2128
srcs = [
2229
"backoff_policy.cc",
2330
"call_context.cc",
2431
"internal/gtest_prod.h",
32+
"operations_client.cc",
33+
"operations_stub.cc",
2534
"status.cc",
2635
],
2736
hdrs = [
2837
"backoff_policy.h",
2938
"call_context.h",
3039
"retry_policy.h",
40+
"operation.h",
41+
"operations_client.h",
42+
"operations_stub.h",
3143
"status.h",
3244
"status_or.h",
3345
],
3446
deps = [
3547
"@com_github_grpc_grpc//:grpc++",
48+
":longrunning_cpp_proto",
3649
],
3750
)
3851

3952
gax_unit_tests = [
4053
"backoff_policy_unittest.cc",
4154
"call_context_unittest.cc",
55+
"operation_unittest.cc",
56+
"operations_stub_unittest.cc",
4257
"retry_policy_unittest.cc",
4358
"status_unittest.cc",
4459
"status_or_unittest.cc",

gax/call_context.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,33 +135,33 @@ class CallContext {
135135
void PrepareGrpcContext(grpc::ClientContext* context);
136136

137137
/**
138-
* @name Register application-specific metadata.
138+
* @brief Register application-specific metadata.
139139
*
140140
* @param key the metadata key.
141141
* @param val the metadata value.
142142
*/
143143
void AddMetadata(std::string key, std::string val);
144144

145145
/**
146-
* @name Set a deadline for the rpc.
146+
* @brief Set a deadline for the rpc.
147147
*/
148148
void SetDeadline(std::chrono::system_clock::time_point deadline);
149149

150150
/**
151-
* @name Accessor for configured rpc deadline.
151+
* @brief Accessor for configured rpc deadline.
152152
*/
153153
std::chrono::system_clock::time_point Deadline() const;
154154

155155
/**
156-
* @name Accessor for method info.
156+
* @brief Accessor for method info.
157157
*/
158158
MethodInfo Info() const;
159159

160160
private:
161161
FRIEND_TEST(CallContext, Basic);
162162
std::chrono::system_clock::time_point deadline_;
163163
std::vector<GrpcContextPolicyFunc> context_policies_;
164-
std::multimap<std::string const, std::string const> metadata_;
164+
std::multimap<std::string, std::string const> metadata_;
165165
MethodInfo const method_info_;
166166
};
167167
}

gax/operation.h

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright 2019 Google Inc. All rights reserved
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef GAPIC_GENERATOR_CPP_GAX_OPERATION_H_
16+
#define GAPIC_GENERATOR_CPP_GAX_OPERATION_H_
17+
18+
#include "google/longrunning/operations.pb.h"
19+
#include "gax/call_context.h"
20+
#include "gax/operations_stub.h"
21+
#include "gax/status.h"
22+
#include "gax/status_or.h"
23+
#include <memory>
24+
25+
namespace google {
26+
namespace gax {
27+
28+
/**
29+
* Operation is a user-visible primitive used to support Long Running Operations
30+
* (LROs).
31+
*
32+
* LROs are service methods that may take a 'long time' (anywhere from
33+
* seconds to days), and instead of blocking for that long return an Operation
34+
* object or an error status. The Operation may contain a result and always
35+
* contains metadata.
36+
*
37+
* A service method that returns `google.longrunning.Operation` and that has
38+
* the correct annotations for its result and metadata types will cause the
39+
* generator to define a client method that returns
40+
* gax::StatusOr<gax::Operation<ResponseT, MetadataT>>.
41+
*
42+
* Example usage:
43+
*
44+
* @code
45+
* gax::StatusOr<gax::Operation<Foo, FooMeta>> res =
46+
* client.GetBigFoo(getBigFooRequest);
47+
* if(!res) {
48+
* ...
49+
* }
50+
*
51+
* operationsClient = client.OperationsClient();
52+
* Operation<Foo, FooMeta> op = *std::move(res);
53+
* while(!op.Done()) {
54+
* gax::Status stat = operationsClient.Update(op);
55+
* if(isPermanentFailure(stat)) {
56+
* ...
57+
* }
58+
* std::cout << "Foo request " << getBigFooRequest().name() << " is " <<
59+
* op.Metadata().percent() << "% done.";
60+
* std::this_thread::sleep(sleep_period());
61+
* }
62+
*
63+
* gax::StatusOr<Result> terminus = op.Result();
64+
* if(!terminus) {
65+
* ...
66+
* }
67+
* Result r = *std::move(terminus);
68+
* @endcode
69+
*/
70+
template <
71+
typename ResponseT, typename MetadataT,
72+
typename std::enable_if<
73+
std::is_base_of<protobuf::Message, ResponseT>::value, int>::type = 0,
74+
typename std::enable_if<
75+
std::is_base_of<protobuf::Message, MetadataT>::value, int>::type = 0>
76+
class Operation final {
77+
public:
78+
// Note: the constructor is intended to be used by GAPIC generated code, not
79+
// users.
80+
explicit Operation(google::longrunning::Operation op) : op_(std::move(op)) {}
81+
82+
/**
83+
* @brief Return the service-provided name of the underlying
84+
* google.longrunning.Operation
85+
*/
86+
std::string const& Name() const { return op_.name(); }
87+
88+
/**
89+
* @brief If Operation::Done(), return the underlying Response, or an error
90+
* code if a problem occurred. Otherwise return an error indicating that the
91+
* Operation has not completed.
92+
*/
93+
gax::StatusOr<ResponseT> Result() const {
94+
if (!Done()) {
95+
return gax::Status{gax::StatusCode::kUnknown,
96+
"operation has not completed=" + Name()};
97+
} else if (op_.has_error()) {
98+
return gax::Status{static_cast<gax::StatusCode>(op_.error().code()),
99+
op_.error().message()};
100+
} else {
101+
auto const& any = op_.response();
102+
if (!any.Is<ResponseT>()) {
103+
return gax::Status{gax::StatusCode::kUnknown,
104+
"invalid result in operation=" + Name()};
105+
}
106+
107+
ResponseT result;
108+
any.UnpackTo(&result);
109+
return std::move(result);
110+
}
111+
}
112+
113+
/**
114+
* @brief Return the most recent metadata received from the service.
115+
*
116+
* The metadata type is application specific. Manipulating it is left to the
117+
* user.
118+
*
119+
* @return the most recent metadata.
120+
*/
121+
MetadataT Metadata() const {
122+
MetadataT m;
123+
op_.metadata().UnpackTo(&m);
124+
return m;
125+
}
126+
127+
/**
128+
* @brief Indicate whether the operation has completed. If true, the Operation
129+
* now contains a result or an error status.
130+
*/
131+
bool Done() const { return op_.done(); }
132+
133+
private:
134+
google::longrunning::Operation op_;
135+
};
136+
137+
} // namespace gax
138+
} // namespace google
139+
140+
#endif // GAPIC_GENERATOR_CPP_GAX_OPERATION_H_

0 commit comments

Comments
 (0)