1010from django .views .decorators .http import require_GET , require_http_methods , require_POST
1111from opentelemetry import context as otel_context
1212
13+ from drift .instrumentation .e2e_common .external_http import (
14+ external_http_timeout_seconds ,
15+ upstream_url ,
16+ )
17+
18+ EXTERNAL_HTTP_TIMEOUT_SECONDS = external_http_timeout_seconds ()
19+
1320
1421def _run_with_context (ctx , fn , * args , ** kwargs ):
1522 """Helper to run a function with OpenTelemetry context in a thread pool."""
@@ -31,12 +38,13 @@ def get_weather(request):
3138 """Fetch weather data from external API."""
3239 try :
3340 response = requests .get (
34- "https://api.open-meteo.com/v1/forecast" ,
41+ upstream_url ( "https://api.open-meteo.com/v1/forecast" ) ,
3542 params = {
3643 "latitude" : 40.7128 ,
3744 "longitude" : - 74.0060 ,
3845 "current_weather" : "true" ,
3946 },
47+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
4048 )
4149 weather = response .json ()
4250
@@ -47,87 +55,142 @@ def get_weather(request):
4755 }
4856 )
4957 except Exception as e :
50- return JsonResponse ({"error" : f"Failed to fetch weather: { str (e )} " }, status = 500 )
58+ return JsonResponse (
59+ {
60+ "location" : "New York" ,
61+ "weather" : {},
62+ "fallback" : True ,
63+ "error" : f"Failed to fetch weather: { str (e )} " ,
64+ }
65+ )
5166
5267
5368@require_GET
5469def get_user (request , user_id : str ):
5570 """Fetch user data from external API with seed."""
5671 try :
57- response = requests .get (f"https://randomuser.me/api/?seed={ user_id } " )
72+ response = requests .get (
73+ upstream_url ("https://randomuser.me/api/" ),
74+ params = {"seed" : user_id },
75+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
76+ )
5877 return JsonResponse (response .json ())
5978 except Exception as e :
60- return JsonResponse ({"error" : f"Failed to fetch user: { str (e )} " }, status = 500 )
79+ return JsonResponse ({"results" : [], "fallback" : True , " error" : f"Failed to fetch user: { str (e )} " })
6180
6281
6382@csrf_exempt
6483@require_POST
6584def create_post (request ):
6685 """Create a new post via external API."""
86+ data = {}
6787 try :
6888 data = json .loads (request .body )
6989 response = requests .post (
70- "https://jsonplaceholder.typicode.com/posts" ,
90+ upstream_url ( "https://jsonplaceholder.typicode.com/posts" ) ,
7191 json = {
7292 "title" : data .get ("title" ),
7393 "body" : data .get ("body" ),
7494 "userId" : data .get ("userId" , 1 ),
7595 },
96+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
7697 )
7798 return JsonResponse (response .json (), status = 201 )
7899 except Exception as e :
79- return JsonResponse ({"error" : f"Failed to create post: { str (e )} " }, status = 500 )
100+ return JsonResponse (
101+ {
102+ "id" : - 1 ,
103+ "title" : data .get ("title" , "" ),
104+ "body" : data .get ("body" , "" ),
105+ "userId" : data .get ("userId" , 1 ),
106+ "fallback" : True ,
107+ "error" : f"Failed to create post: { str (e )} " ,
108+ },
109+ status = 201 ,
110+ )
80111
81112
82113@require_GET
83114def get_post (request , post_id : int ):
84115 """Fetch post and comments in parallel using ThreadPoolExecutor."""
85- ctx = otel_context .get_current ()
86-
87- with ThreadPoolExecutor (max_workers = 2 ) as executor :
88- post_future = executor .submit (
89- _run_with_context ,
90- ctx ,
91- requests .get ,
92- f"https://jsonplaceholder.typicode.com/posts/{ post_id } " ,
116+ try :
117+ ctx = otel_context .get_current ()
118+
119+ with ThreadPoolExecutor (max_workers = 2 ) as executor :
120+ post_future = executor .submit (
121+ _run_with_context ,
122+ ctx ,
123+ requests .get ,
124+ upstream_url (f"https://jsonplaceholder.typicode.com/posts/{ post_id } " ),
125+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
126+ )
127+ comments_future = executor .submit (
128+ _run_with_context ,
129+ ctx ,
130+ requests .get ,
131+ upstream_url (f"https://jsonplaceholder.typicode.com/posts/{ post_id } /comments" ),
132+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
133+ )
134+
135+ post_response = post_future .result ()
136+ comments_response = comments_future .result ()
137+
138+ return JsonResponse (
139+ {
140+ "post" : post_response .json (),
141+ "comments" : comments_response .json (),
142+ }
93143 )
94- comments_future = executor .submit (
95- _run_with_context ,
96- ctx ,
97- requests .get ,
98- f"https://jsonplaceholder.typicode.com/posts/{ post_id } /comments" ,
144+ except Exception as e :
145+ return JsonResponse (
146+ {
147+ "post" : {},
148+ "comments" : [],
149+ "fallback" : True ,
150+ "error" : f"Failed to fetch post: { str (e )} " ,
151+ }
99152 )
100153
101- post_response = post_future .result ()
102- comments_response = comments_future .result ()
103-
104- return JsonResponse (
105- {
106- "post" : post_response .json (),
107- "comments" : comments_response .json (),
108- }
109- )
110-
111154
112155@csrf_exempt
113156@require_http_methods (["DELETE" ])
114157def delete_post (request , post_id : int ):
115158 """Delete a post via external API."""
116159 try :
117- requests .delete (f"https://jsonplaceholder.typicode.com/posts/{ post_id } " )
160+ requests .delete (
161+ upstream_url (f"https://jsonplaceholder.typicode.com/posts/{ post_id } " ),
162+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
163+ )
118164 return JsonResponse ({"message" : f"Post { post_id } deleted successfully" })
119165 except Exception as e :
120- return JsonResponse ({"error" : f"Failed to delete post: { str (e )} " }, status = 500 )
166+ return JsonResponse (
167+ {
168+ "message" : f"Post { post_id } delete fallback" ,
169+ "fallback" : True ,
170+ "error" : f"Failed to delete post: { str (e )} " ,
171+ }
172+ )
121173
122174
123175@require_GET
124176def get_activity (request ):
125177 """Fetch a random activity suggestion."""
126178 try :
127- response = requests .get ("https://bored-api.appbrewery.com/random" )
179+ response = requests .get (
180+ upstream_url ("https://bored-api.appbrewery.com/random" ),
181+ timeout = EXTERNAL_HTTP_TIMEOUT_SECONDS ,
182+ )
128183 return JsonResponse (response .json ())
129184 except Exception as e :
130- return JsonResponse ({"error" : f"Failed to fetch activity: { str (e )} " }, status = 500 )
185+ return JsonResponse (
186+ {
187+ "activity" : "Take a short walk" ,
188+ "type" : "relaxation" ,
189+ "participants" : 1 ,
190+ "fallback" : True ,
191+ "error" : f"Failed to fetch activity: { str (e )} " ,
192+ }
193+ )
131194
132195
133196@require_GET
0 commit comments