Пример #1
0
            def handler(res):
                if res.status_code not in HTTP_OK:
                    raise BatchExecuteError(res)
                if not self._return_result:
                    return

                for index, raw_response in enumerate(
                        res.raw_body.split('--XXXsubpartXXX')[1:-1]):
                    request = self._requests[index]
                    job = self._batch_jobs[index]
                    res_parts = raw_response.strip().split('\r\n')
                    raw_status, raw_body = res_parts[3], res_parts[-1]
                    _, status_code, status_text = raw_status.split(' ', 2)

                    response_dict = {
                        'method': request.method,
                        'url': self._url_prefix + request.url,
                        'headers': request.headers,
                        'status_code': int(status_code),
                        'status_text': status_text,
                        'body': raw_body
                    }

                    response = Response(response_dict, self.response_mapper)

                    if int(status_code) in HTTP_OK:
                        job.update('done', response)
                    else:
                        job.update('error', response)
Пример #2
0
    def commit(self):
        """Execute the queued API requests in a single HTTP call.

        If `return_response` was set to ``True`` during initialization, the
        responses are saved within an :class:`arango.batch.BatchJob` object
        for later retrieval via its :func:`~arango.batch.BatchJob.result`
        method

        :raises arango.exceptions.BatchExecuteError: if the batch request
            cannot be executed
        """
        try:
            if not self._requests:
                return
            raw_data = ''
            for content_id, request in enumerate(self._requests, start=1):
                raw_data += '--XXXsubpartXXX\r\n'
                raw_data += 'Content-Type: application/x-arango-batchpart\r\n'
                raw_data += 'Content-Id: {}\r\n\r\n'.format(content_id)
                raw_data += '{}\r\n'.format(request.stringify())
            raw_data += '--XXXsubpartXXX--\r\n\r\n'

            res = self.post(
                endpoint='/_api/batch',
                headers={
                    'Content-Type':
                    ('multipart/form-data; boundary=XXXsubpartXXX')
                },
                data=raw_data,
            )
            if res.status_code not in HTTP_OK:
                raise BatchExecuteError(res)
            if not self._return_result:
                return

            for index, raw_response in enumerate(
                    res.raw_body.split('--XXXsubpartXXX')[1:-1]):
                request = self._requests[index]
                handler = self._handlers[index]
                job = self._batch_jobs[index]
                res_parts = raw_response.strip().split('\r\n')
                raw_status, raw_body = res_parts[3], res_parts[-1]
                _, status_code, status_text = raw_status.split(' ', 2)
                try:
                    result = handler(
                        Response(method=request.method,
                                 url=self._url_prefix + request.endpoint,
                                 headers=request.headers,
                                 http_code=int(status_code),
                                 http_text=status_text,
                                 body=raw_body))
                except ArangoError as err:
                    job.update(status='error', result=err)
                else:
                    job.update(status='done', result=result)
        finally:
            self._requests = []
            self._handlers = []
            self._batch_jobs = []
Пример #3
0
    def commit(self):
        """Execute the queued requests in a single batch API request.

        If **return_result** parameter was set to True during initialization,
        :class:`arango.job.BatchJob` instances are populated with results.

        :return: Batch jobs or None if **return_result** parameter was set to
            False during initialization.
        :rtype: [arango.job.BatchJob] | None
        :raise arango.exceptions.BatchStateError: If batch state is invalid
            (e.g. batch was already committed or size of response from server
            did not match the expected).
        :raise arango.exceptions.BatchExecuteError: If commit fails.
        """
        if self._committed:
            raise BatchStateError('batch already committed')
        else:
            self._committed = True

        if len(self._queue) == 0:
            return self.jobs

        # Boundary used for multipart request
        boundary = uuid4().hex

        # Build the batch request payload
        buffer = []
        for req, job in self._queue.values():
            buffer.append('--{}'.format(boundary))
            buffer.append('Content-Type: application/x-arango-batchpart')
            buffer.append('Content-Id: {}'.format(job.id))
            buffer.append('\r\n' + self._stringify_request(req))
        buffer.append('--{}--'.format(boundary))

        request = Request(
            method='post',
            endpoint='/_api/batch',
            headers={
                'Content-Type':
                'multipart/form-data; boundary={}'.format(boundary)
            },
            data='\r\n'.join(buffer),
        )
        with suppress_warning('requests.packages.urllib3.connectionpool'):
            resp = self._conn.send_request(request)

        if not resp.is_success:
            raise BatchExecuteError(resp, request)

        if not self._return_result:
            return None

        url_prefix = resp.url.strip('/_api/batch')
        raw_resps = resp.raw_body.split('--{}'.format(boundary))[1:-1]

        if len(self._queue) != len(raw_resps):
            raise BatchStateError(
                'expecting {} parts in batch response but got {}'.format(
                    len(self._queue), len(raw_resps)))
        for raw_resp in raw_resps:
            # Parse and breakdown the batch response body
            resp_parts = raw_resp.strip().split('\r\n')
            raw_content_id = resp_parts[1]
            raw_body = resp_parts[-1]
            raw_status = resp_parts[3]
            job_id = raw_content_id.split(' ')[1]
            _, status_code, status_text = raw_status.split(' ', 2)

            # Update the corresponding batch job
            queued_req, queued_job = self._queue[job_id]

            queued_job._status = 'done'
            resp = Response(method=queued_req.method,
                            url=url_prefix + queued_req.endpoint,
                            headers={},
                            status_code=int(status_code),
                            status_text=status_text,
                            raw_body=raw_body)
            queued_job._response = self._conn.prep_response(resp)

        return self.jobs
Пример #4
0
    def commit(self):
        """Execute the queued API requests in a single HTTP call.

        If `return_response` was set to ``True`` during initialization, the
        responses are saved within an :class:`arango.batch.BatchJob` object
        for later retrieval via its :func:`arango.batch.BatchJob.result`
        method

        :returns: list of :class:`arango.batch.BatchJob` or None
        :rtype: [arango.batch.BatchJob] | None

        :raises arango.exceptions.BatchExecuteError: if the batch request
            cannot be executed
        """

        lock_res = self._lock.acquire(timeout=self._batch_submit_timeout)

        if not lock_res:
            raise BatchExecuteError('Unable to reaccquire lock within time '
                                    'period. Some thread must be holding it.')

        try:
            if len(self._requests) == 0:
                return

            raw_data_list = []
            for content_id, one_request in enumerate(self._requests, start=1):
                raw_data_list.append('--XXXsubpartXXX\r\n')
                raw_data_list.append(
                    'Content-Type: application/x-arango-batchpart\r\n')
                raw_data_list.append(
                    'Content-Id: {}\r\n\r\n'.format(content_id))
                raw_data_list.append('{}\r\n'.format(one_request.stringify()))
            raw_data_list.append('--XXXsubpartXXX--\r\n\r\n')
            raw_data = ''.join(raw_data_list)

            batch_request = Request(
                method='post',
                endpoint='/_api/batch',
                headers={
                    'Content-Type':
                    ('multipart/form-data; boundary=XXXsubpartXXX')
                },
                data=raw_data)

            def handler(res):
                if res.status_code not in HTTP_OK:
                    raise BatchExecuteError(res)
                if not self._return_result:
                    return

                for index, raw_response in enumerate(
                        res.raw_body.split('--XXXsubpartXXX')[1:-1]):
                    request = self._requests[index]
                    job = self._batch_jobs[index]
                    res_parts = raw_response.strip().split('\r\n')
                    raw_status, raw_body = res_parts[3], res_parts[-1]
                    _, status_code, status_text = raw_status.split(' ', 2)

                    response_dict = {
                        'method': request.method,
                        'url': self._url_prefix + request.url,
                        'headers': request.headers,
                        'status_code': int(status_code),
                        'status_text': status_text,
                        'body': raw_body
                    }

                    response = Response(response_dict, self.response_mapper)

                    if int(status_code) in HTTP_OK:
                        job.update('done', response)
                    else:
                        job.update('error', response)

            BaseConnection.handle_request(self, batch_request, handler,
                                          job_class=BaseJob)\
                .result(raise_errors=True)

            return self._batch_jobs
        finally:
            self._requests = []
            self._batch_jobs = []
            self._lock.release()