async def _push_to_dynatrace(context: Context, lines_batch: List[IngestLine]):
    ingest_input = "\n".join([line.to_string() for line in lines_batch])
    if context.print_metric_ingest_input:
        context.log("Ingest input is: ")
        context.log(ingest_input)
    ingest_response = await context.session.post(
        url=f"{context.dynatrace_url.rstrip('/')}/api/v2/metrics/ingest",
        headers={
            "Authorization": f"Api-Token {context.dynatrace_api_key}",
            "Content-Type": "text/plain; charset=utf-8"
        },
        data=ingest_input,
        verify_ssl=context.require_valid_certificate)

    if ingest_response.status == 401:
        context.dynatrace_connectivity = DynatraceConnectivity.ExpiredToken
        raise Exception("Expired token")
    elif ingest_response.status == 403:
        context.dynatrace_connectivity = DynatraceConnectivity.WrongToken
        raise Exception(
            "Wrong token - missing 'Ingest metrics using API V2' permission")
    elif ingest_response.status == 404 or ingest_response.status == 405:
        context.dynatrace_connectivity = DynatraceConnectivity.WrongURL
        raise Exception("Wrong URL")

    ingest_response_json = await ingest_response.json()
    context.dynatrace_request_count[
        ingest_response.status] = context.dynatrace_request_count.get(
            ingest_response.status, 0) + 1
    context.dynatrace_ingest_lines_ok_count += ingest_response_json.get(
        "linesOk", 0)
    context.dynatrace_ingest_lines_invalid_count += ingest_response_json.get(
        "linesInvalid", 0)
    context.log(f"Ingest response: {ingest_response_json}")
    await log_invalid_lines(context, ingest_response_json, lines_batch)
async def push_ingest_lines(context: Context,
                            fetch_metric_results: List[IngestLine]):
    lines_sent = 0
    maximum_lines_threshold = context.maximum_metric_data_points_per_minute
    start_time = time.time()
    try:
        lines_batch = []
        for result in fetch_metric_results:
            lines_batch.append(result)
            lines_sent += 1
            if len(lines_batch) >= context.metric_ingest_batch_size:
                await _push_to_dynatrace(context, lines_batch)
                lines_batch = []
            if lines_sent >= maximum_lines_threshold:
                await _push_to_dynatrace(context, lines_batch)
                lines_dropped_count = len(
                    fetch_metric_results) - maximum_lines_threshold
                context.dynatrace_ingest_lines_dropped_count = lines_dropped_count
                context.log(
                    f"Number of metric lines exceeded maximum {maximum_lines_threshold}, dropped {lines_dropped_count} lines"
                )
                return
        if lines_batch:
            await _push_to_dynatrace(context, lines_batch)
    except Exception as e:
        if isinstance(e, InvalidURL):
            context.dynatrace_connectivity = DynatraceConnectivity.WrongURL
        context.log(
            f"Failed to push ingest lines to Dynatrace due to {type(e).__name__} {e}"
        )
    finally:
        context.push_to_dynatrace_execution_time = time.time() - start_time
        context.log(
            f"Finished uploading metric ingest lines to Dynatrace in {context.push_to_dynatrace_execution_time} s"
        )